;
程序计数器是线程私有的内存区域,这个区域是Java虚拟机中唯一一个没有限制 OutOfMemoryError
的内存区域。之所以需要它是因为Java的多线程机制是通过轮流切换分配处理器执行时间来实现的,所以会涉及到线程的暂停和重启,而在一个线程中如果正在执行Java方法的话,这个计数器就回去记录当前正在执行的虚拟机字节码,一旦被暂停,恢复只需要从程序计数器记录的为止继续执行就可以。
但是,如果线程中执行的是一个Native方法,那么程序计数器是不会去记录的,所以此时的程序计数器为空。
Java虚拟机栈也是线程私有的。一条线程启动就会为它建立一个虚拟机栈。
在线程中每有一个Java方法被调用就会创建一个 “栈帧” 。每个 “栈帧” 会保存执行该方法所需的局部变量表(一般Java程序员喜欢用这个部分来代表栈)、操作数栈、动态链接以及方法出口等信息。
如果一个线程中有过多的 “栈帧” 要入到虚拟机栈中,即短时间内调用了过多的方法,就会造成 -- 栈益处 -- ,即 StackOverflowError 错误。
在这个内存区域中,如果虚拟机需要扩展内存,但没有申请到足够的内存,就会抛出 OutOfMemoryError 错误。
和虚拟机栈有些类似,但它是为Native方法提供服务的。
Java的堆内存是Java虚拟机所管理的内存中最大的一块。它是所有线程所共享的,用于存放对象实例和数组,Java虚拟机的GC主要就发生在这个地方。因此这块区域也叫做"GC堆"。
Java堆的内存可以按照垃圾回收算法【分代回收】分为【新生代区】和【老年区】,进一步的,【新生代区】可以分为【Eden区】、【From Survivor区】和【To Survivor区】。
从内存角度来说,Java堆内存又被划分为线程共享的内存区域和每个线程私有的内存区域。
在Java堆区域中,如果没有内存分配给要创建的实例,并且堆也不能够再扩展,就会抛出 OutOfMemoryError
错误。
在 Java8 之后, Heap Segment 真正意义上的是由 Young Generiation 和 Old Generiation 组成的。对象在其中是 标记复制算法 来判定一个对象是否应该被清理掉。
Heap Segment 中发生的GC称为 Major GC ,只会影响 Heap Segment 区。
这个区域发生的GC称为 Minor GC
。
-XX:MaxTenuringThreshold
该命令来调整阀值)时,这个对象将被复制到 Old Generiation 区中,此时该对象将会变的相对安全,因为 Old Segment 区的GC频率相对较低。 这个区域发送的GC成为 Full GC
。
OutOfMemoryError
。 Java的方法区和Java的堆内存一样是被线程所共有的。它主要存放虚拟机加载的类信息、常量、静态变量、即时编译产生的代码等。
一些地方会将方法区合并到Java堆中一起去说。把它作为“永久代”。这在Hot-Spot虚拟机而言成立,但是一般来说是不成立的。
Java的方法区如果内存不够分配的话,也是会抛出 OutOfMemoryError
错误的。也就是如果加载过多类到方法区的话,可能会造成方法区内存益处。
在GC检查对象的是否可以回收时,是根据对象是否可到达引用练顶端的 GC Roots
对象来判断的。 GC Roots
对象一般是虚拟机栈中变量表中引用的对象、类静态属性引用的对象、常量对象、JNI传到底层的对象。就是说,一个对象如果溯源不到这几种类型的对象的话,就认为它是无法到达的,那么它将会在GC时被回收。
在JDK 1.2之后,Java扩充了4种引用类型定义:
即我们平时通过new关键字创建出来的的对象的引用,只要强引用还存在,那么这些对象就一定不回被回收,即使时抛出 OutOfMemoryError
。什么时候强引用会不存在呢?当一个方法执行完,栈帧中的变量表将会被清理,在该方法中创建使用的临时强引用就会被清理掉,之后,原本它指向的对象就被变的不可到达。
用来描述一些有用但不是必须的对象,即通过 SoftReference
创建的对象,它们将会在原本确定要发生内存溢出前的一次GC中被回收,如果回收完内存还是不够,Java堆就会抛出 OutOfMemoryError
错误。就是说,在触发内存溢出发生前,这些对象是和强引用一样,只要引用还在,就不会被回收。
用来描述一些不必须的对象,即通过 WeakReference
创建的对象。弱引用对象的生命周期只有一次GC。
一个对象的存在与否完全不受虚引用的影响,它唯一的用处就是可以用来监测一个对象是否被回收。
运行时常量池主要存放类中编译时期生成的常量,当然也可以动态的往里面添加。
比如:
"abc".intern(); 复制代码
这个方法首先会检查运行时常量池中是否有这个字符串,有的话取出来用,没有的话生成一个并存到常量池中。
再比如,运行过程中生成通过 static
修饰的String时,也会加入到常量池中。对于String而言, 常量 + 常量
生成的也是常量,但是 常量 + 变量
生成的就是变量了。
Dalvik虚拟机是Google按照JVM虚拟机规范定制的虚拟机,它更符合移动设备的环境要求。与标准虚拟机不同:
.dex
文件,这种格式的文件体积更小。而JVM规范的是 .class
文件。