1.Java中哪些组件需要用到内存
1)堆
用于存储Java对象的内存区域,堆的大小在JVM启动时就一次向OS申请完成,通过-Xmx和-Xms两个选项来控制大小,前者表示堆的最大大小,后者表示堆的初始大小。一旦分配完成,堆的大小就将固定,不能在内存不够时再向OS重新申请,同时当内存空闲时也不能将多余的空间还给OS。
Java堆中内存空间的管理由JVM来控制,对象创建由Java应用程序控制,但是对象所占的空间释放由管理堆内存的垃圾收集器(GC)来完成。根据垃圾收集(GC)算法的不同,内存回收的方式和时机也会不同。
2)线程
JVM运行实际程序的实体是线程,当然线程需要内存空间来存储一些必要的数据。每个线程创建时JVM都会为它创建一个栈。
3)类和类加载器
它们也被存储在堆中,这个区域叫做永久区(PermGen区)。
JVM只会加载一个类到内存一次,并且JVM也不会对失效的类做卸载,通常一个类能够被卸载有如下一些条件需要被满足:
(1)堆中没有对表示该类加载器的java.lang.ClassLoader对象的引用。
(2)堆中没有对表示该类加载器的类的任何java.lang.Class对象的引用。
(3)堆上该类加载器加载的任何类的所有对象都不再存活。
4)NIO
NIO使用java.nio.ByteBuffer.allocateDirect()分配内存时使用的是本机内存而不是JVM堆上的内存。
直接ByteBuffer对象会自动清理本机缓冲区,但这个过程只能作为JVM堆GC的一部分来执行,因此它们不会自动响应施加在本机内存上的压力。GC仅在Java堆被填满,以至于无法为堆分配请求提供服务时发生,或者在Java应用程序中显示请求发生。
当前很多NIO框架都在代码中显示调用System.gc()来释放NIO持有的内存。但是这种方式会影响应用程序的性能,因为会增加GC的次数,可以通过设置-XX:+disableExplicitGC来控制System.gc()的影响。
5)JNI
会增加Java程序运行时的本机内存占用。
2.JVM内存结构
JVM是按照运行时数据的存储结构来划分内存结构的,JVM在运行Java程序时,将他们划分成几种不同格式的数据,分别存储在不同的区域,这些数据统一称为运行时数据(Running Data)。
JVM规范将运行时数据划分为6中:
1)PC寄存器
严格来说是一个数据结构,用于保存当前正在执行的程序的内存地址。
注:JVM规范只定义了Java方法需要记录指针信息,而对于Native方法,并没有要求记录执行的指针地址。
2)栈
每当创建一个线程时,JVM就会为这个线程创建一个对应的栈,栈中的每个数据单元称为栈帧,栈帧是与每个方法关联起来的,每运行一个方法就创建一个栈帧,每个栈帧会包含一些内部变量,操作栈和方法返回值等信息。
3)堆
堆是存储Java对象的地方,它是JVM管理Java对象的核心存储区域。
每一个存储在堆中的Java对象都会是这个对象的类的一个副本,它会复制包括继承自它父类的所有非静态属性。
堆是被所有Java线程所共享的,所以对它的访问需要注意同步问题,方法和对应的属性都需要保证一致性。
4)方法区
用于存储类结构信息的地方,在将一个class文件解析成JVM能识别的几个部分,这些不同的部分在这个class被加载到JVM时,会被存储在不同的数据结构中,其中的常量池,域,方法数据,方法体,构造函数,包括类中的专用方法等都存储在这个区域。
这个存储区域属于堆的一部分,通常称为永久区。被所有线程共享,可以通过参数设置它的大小。
这个存储区域的大小一般在程序启动后的一段时间内就是固定的了。但是假如项目中存在对类的动态编译,而且是同样一个类的多次编译,那么需要观察方法区的大小是否能满足存储。
虽然它存储的信息相对比较稳定,也不会频繁地被垃圾收集器(GC)扫描,但是仍然会被JVM的垃圾收集器(GC)管理。
5)本地方法区
为JVM运行Native方法准备的空间,和前面介绍的栈的作用类似,由于很多Native方法都是用C语言实现的,所以它通常又叫C栈。
使用这个区域的代码有:
(1)常规的Native方法。
(2)JIT编译技术把一些Java方法重新编译为Native代码。
6)运行时常量池
代表运行时class文件中的常量表。它包括几种常量:编译期的数字常量,方法或者域的引用。
它是方法区的一部分。
3.JVM内存分配策略
JVM内存分配主要基于两种,分别是堆和栈。
栈的分配是和线程绑在一起的,栈的基本数据单元是栈帧,对应每个执行方法,用来保存参数,局部变量,中间计算过程和其他数据。
栈中主要存放一些基本类型的变量数据(int,short,long,byte,float,double,boolean,char)和对象句柄(引用)。存取速度比较快,仅次于寄存器,栈数据可以共享,内存空间在线程结束时自动回收。缺点是,存在栈中的数据大小与生存期必须是确定的,这也导致缺乏了其灵活性。
这些变量的在运行时需要存储空间,同时在执行指令时JVM也需要知道栈的大小,这些数据都会在Javac编译这段代码时就已经确定。
每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用程序所有的线程共享。
堆内存是自动初始化的,所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配的。也就是说在建立一个对象时两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在栈中分配的内存只是一个指向这个堆对象的引用而已。
堆是由垃圾收集器(GC)来负责的,优点是可以动态分配内存大小,生存期也不用事先告诉编译器,因为它是在运行时动态分配内存的,GC会自动收走不再使用的数据。缺点是存取速度较慢。
4.JVM内存回收策略
垃圾收集器(GC)的任务有:正确检测出垃圾对象,释放垃圾对象占用的内存空间。
1)如何检测垃圾
只要是某个对象不再被其它活动对象引用,那么这个对象就是垃圾对象。这里的活动对象指的是能够被一个根对象集合到达的对象。
根对象集合的内容有:
(1)方法中局部变量区中对象的引用
(2)Java操作栈中的对象引用
(3)常量池中的对象引用
(4)本地方法中持有的对象引用
(5)类的Class对象
5.垃圾收集算法
略
6.参考资料
《深入分析 Java Web 技术内幕》
相关推荐
JVM 内存管理之道 JVM垃圾回收机制 JVM GC组合 JVM 内存监控工具
JVM内存管理和垃圾回收 JVM内存管理和垃圾回收 JVM内存管理和垃圾回收
sun公司出版的jvm运行机制管理丛书,需要深入jvm的同学可以下载来看看
详细介绍了JVM 内存管理相关知识 内存空间( VM运行时数据区域) ◦ 内存结构 ◦ 内存空间 内存分配 内存回收(GC) 内存分析工具
JVM内存管理知识思维导图.png
对于深入掌握的java的人士,对于内存管理是不得不看的东西
Sun JVM原理与内存管理
从JVM内存管理的角度谈谈静态方法和静态属性
JVM内存管理和垃圾回收.pdf
JVM内存管理面试常见问题全解.doc
JVM内存管理和垃圾回收参考.pdf
JVM内存管理和垃圾回收知识.pdf
JVM内存管理白皮书[借鉴].pdf
JVM内存管理的介绍,编写GC友好的代码。 本材料主要关心 Sun Hotspot JVM 6的内存管理 Sun Hotspot JVM 6的GC模型 主要针对JVM6的GC模型,但也会简单介绍Java 7的G1 编写GC友好代码的一些技巧
你对JVM内存组成结构和JVM垃圾回收机制是否熟悉,这里和大家简单分享一下,希望对你的学习有所帮助,首先来看一下JVM内存结构,它是由堆、栈、本地方法栈、方法区等部分组成,结构图如下所示。