网页传奇游戏推广员,镇江seo,开网站建设,重庆 网站定制1、JVM体系结构 2、JVM运行时数据区 3、JVM内存模型
JVM运行时内存 共享内存区 线程内存区 3.1、共享内存区
共享内存区 持久带(方法区 其他) 堆(Old Space Young Space(den S0 S1)) 持久代#xff1a;
JVM用持久带#xff08;Permanent Space#xff09;实现方法… 1、JVM体系结构 2、JVM运行时数据区 3、JVM内存模型
JVM运行时内存 共享内存区 线程内存区 3.1、共享内存区
共享内存区 持久带(方法区 其他) 堆(Old Space Young Space(den S0 S1)) 持久代
JVM用持久带Permanent Space实现方法区主要存放所有已加载的类信息方法信息常量池等等。可通过-XX:PermSize和-XX:MaxPermSize来指定持久带初始化值和最大值。Permanent Space并不等同于方法区只不过是Hotspot JVM用Permanent Space来实现方法区而已有些虚拟机没有Permanent Space而用其他机制来实现方法区。
堆(heap):
主要用来存放类的对象实例信息包括new操作实例化的对象和定义的数组。
堆分为Old Space又名Tenured Generation和Young Space。Old Space主要存放应用程序中生命周期长的存活对象Eden(伊甸园)主要存放新生的对象S0和S1是两个大小相同的内存区域主要存放每次垃圾回收后Eden存活的对象作为对象从Eden过渡到Old Space的缓冲地带S是指英文单词Survivor Space。堆之所以要划分区间是为了方便对象创建和垃圾回收. 3.2、线程内存区 线程内存区JVM栈
线程内存区单个线程内存单个线程内存.......
单个线程内存PC RegsterJVM栈本地方法栈
JVM栈栈帧栈帧.....
栈帧局域变量区操作数区帧数据区
在Java中一个线程会对应一个JVM栈(JVM Stack)JVM栈里记录了线程的运行状态。JVM栈以栈帧为单位组成一个栈帧代表一个方法调用。栈帧由三部分组成局部变量区、操作数栈、帧数据区。
线程在栈区不能共享数据只能通过复制共享区的数据作为一块缓存所有多线程写会有bugvoliate使得取到的数据不做缓存是实时更新的。关键字 volatile 是轻量级的同步机制。
Volatile 变量对于all线程的可见性指当一条线程修改了这个变量的值新值对于其他 线程来说是可见的、立即得知的。 Volatile 变量在多线程下不一定安全因为他只有可见性、有序性但是没有原子性。 二、JVM内存空间管理
JVM把内存划分了如下几个区域 共享内存区 持久带(方法区 其他) 堆(Old Space Young Space(den S0 S1))
Java 内存模型和线程:
每个线程都有一个工作内存线程只可以修改自己工作内存中的数据然后再同步回主内存主内存由多个内存共享。 2.1 方法区共享内存区的持久带
方法区 (又称为持久代)要加载的类的信息名称、修饰符等、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息。方法区域也是全局共享的当开发人员调用类对象中的getName、isInterface等方法来获取信息时这些数据都来源于方法区。
在一定条件下它也会被GC当方法区域要使用的内存超过其允许的大小时会抛出OutOfMemoryPermGen Space异常。的错误信息。在Sun JDK中这块区域对应Permanet Generation默认最小值为16MB最大值为64MB可通过-XX:PermSize及-XX:MaxPermSize来指定最小值和最大值。
在Hotspot虚拟机中这块区域对应的是Permanent Generation(持久代)一般的方法区上执行的垃圾收集是很少的因此方法区又被称为持久代的原因之一但这也不代表着在方法区上完全没有垃圾收集其上的垃圾收集主要是针对常量池的内存回收和对已加载类的卸载。在方法区上进行垃圾收集条件苛刻而且相当困难关于其回后面再介绍。
运行时常量池Runtime Constant Pool是方法区的一部分用于存储编译期就生成的字面常量、符号引用、翻译出来的直接引用符号引用就是编码是用字符串表示某个变量、接口的位置直接引用就是根据符号引用翻译出来的地址将在类链接阶段完成翻译
运行时常量池除了存储编译期常量外也可以存储在运行时间产生的常量比如String类的intern()方法作用是String维护了一个常量池如果调用的字符“abc”已经在常量池中则返回池中的字符串地址否则新建一个常量加入池中并返回地址。JVM方法区的相关参数最小值--XX:PermSize最大值 --XX:MaxPermSize。 2.2 堆区(堆区由所有线程共享)
堆用于存储对象实例及数组值可以认为Java中所有通过new创建的对象的内存都在此分配堆区由所有线程共享。Heap中对象所占用的内存由GC进行回收在32位操作系统上最大为2GB在64位操作系统上则没有限制其大小可通过-Xms和-Xmx来控制-Xms为JVM启动时申请的最小Heap内存默认为物理内存的1/64但小于1GB-Xmx为JVM可申请的最大Heap内存默认为物理内存的1/4但小于1GB默认当空余堆内存小于40%时JVM会增大Heap到-Xmx指定的大小可通过-XX:MinHeapFreeRatio来指定这个比例当空余堆内存大于70%时JVM会减小Heap的大小到-Xms指定的大小可通过-XX:MaxHeapFreeRatio来指定这个比例对于运行系统而言为避免在运行时频繁调整Heap 的大小通常将-Xms和-Xmx的值设成一样。
堆区是理解JavaGC机制最重要的区域。在JVM所管理的内存中堆区是最大的一块堆区也是JavaGC机制所管理的主要内存区域堆区由所有线程共享在虚拟机启动时创建。堆区用来存储对象实例及数组值可以认为java中所有通过new创建的对象都在此分配。 2.3 本地方法栈Native Method Stack
本地方法栈用于支持native方法的执行存储了每个native方法调用的状态。本地方法栈和虚拟机方法栈运行机制一致它们唯一的区别就是虚拟机栈是执行Java方法的而本地方法栈是用来执行native方法的在很多虚拟机中如Sun的JDK默认的HotSpot虚拟机会将本地方法栈与虚拟机栈放在一起使用。 2.4 虚拟机栈JVM Stack(线程私有)
JVM方法栈为线程私有其在内存分配上非常高效。当方法运行完毕时其对应的栈帧所占用的内存也会自动释放。当JVM方法栈空间不足时会抛出StackOverflowError的错误在Sun JDK中可以通过-Xss来指定其大小。
虚拟机栈占用的是操作系统内存每个线程都对应着一个虚拟机栈它是线程私有的而且分配非常高效。一个线程的每个方法在执行的同时都会创建一个栈帧Statck Frame栈帧中存储的有局部变量表、操作站、动态链接、方法出口等当方法被调用时栈帧在JVM栈中入栈当方法执行完成时栈帧出栈。
局部变量表中存储着方法的相关局部变量包括各种基本数据类型对象的引用返回地址等。在局部变量表中只有long和double类型会占用2个局部变量空间Slot对于32位机器一个Slot就是32个bit其它都是1个Slot。需要注意的是局部变量表是在编译时就已经确定好的方法运行所需要分配的空间在栈帧中是完全确定的在方法的生命周期内都不会改变。
虚拟机栈中定义了两种异常如果线程调用的栈深度大于虚拟机允许的最大深度则抛出StatckOverFlowError栈溢出不过多数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的)所以线程可以一直申请栈直到内存不足此时会抛出OutOfMemoryError内存溢出。 2.5 程序计数器Program Counter Register)(线程私有)
程序计数器是一个比较小的内存区域可能是CPU寄存器或者操作系统内存其主要用于指示当前线程所执行的字节码执行到了第几行可以理解为是当前线程的行号指示器。字节码解释器在工作时会通过改变这个计数器的值来取下一条语句指令。 每个程序计数器只用来记录一个线程的行号所以它是线程私有一个线程就有一个程序计数器的。
如果程序执行的是一个Java方法则计数器记录的是正在执行的虚拟机字节码指令地址如果正在执行的是一个本地native由C语言编写完成方法则计数器的值为Undefined由于程序计数器只是记录当前指令地址所以不存在内存溢出的情况因此程序计数器也是所有JVM内存区域中唯一一个没有定义OutOfMemoryError的区域。 三、内存溢出与内存泄漏
内存泄漏分配出去的内存回收不了
内存溢出指系统内存不够用了 1、堆溢出
可以分为内存泄漏和内存溢出这两种情况都会抛出OutOfMemoryError:java heap space异常 a、内存泄漏
内存泄漏是指对象实例在新建和使用完毕后仍然被引用没能被垃圾回收释放一直积累直到没有剩余内存可用。如果内存泄露我们要找出泄露的对象是怎么被GC ROOT引用起来然后通过引用链来具体分析泄露的原因。分析内存泄漏的工具有Jprofilervisualvm等。 public class OOMTest {
public static void main(String[] args) { ListUUID list new ArrayListUUID(); while(true){ list.add(UUID.randomUUID()); } }
}
看看控制台的输出结果因为我这边的JVM设置的参数内存足够大所以需要等待一定的时间才能看到效果 b、内存溢出
内存溢出是指当我们新建一个实力对象时实例对象所需占用的内存空间大于堆的可用空间。如果出现了内存溢出问题这往往是程序本生需要的内存大于了我们给虚拟机配置的内存这种情况下我们可以采用调大-Xmx来解决这种问题。 public class OOMTest_1 { public static void main(String args[]){ Listbyte[] byteList new ArrayListbyte[](); byteList.add(new byte[1000 * 1024 * 1024]); }
}
2、栈溢出
栈JVM Stack存放主要是栈帧( 局部变量表, 操作数栈 , 动态链接 , 方法出口信息 )的地方。注意区分栈和栈帧栈里包含栈帧。
与线程栈相关的内存异常有两个:
aStackOverflowError(方法调用层次太深内存不够新建栈帧)
bOutOfMemoryError线程太多内存不够新建线程 a、java.lang.StackOverflowError
栈溢出抛出java.lang.StackOverflowError错误出现此种情况是因为方法运行的时候请求新建栈帧时栈所剩空间小于栈帧所需空间。例如通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 public class SOFTest { public void stackOverFlowMethod(){ stackOverFlowMethod(); } /**