您的位置:首页 > 编程语言 > Java开发

Java内存分配

2016-03-03 18:58 309 查看

内存分配



1. 程序计数器(线程私有,当前线程执行字节码的行号指示器,Native方法为空Undefined)

2. 虚拟机栈(线程私有,Java方法,每个方法在执行的时候都会创建栈帧,用于储存局部变量表【对象引用+基本数据类型】,操作数栈,动态链接,方法出口等,每个方法的执行和完成,对应着栈帧在虚拟机栈的入栈和出栈)

3. 本地方法栈(线程私有,Native方法)

4. (线程共享,几乎所有对象都在堆分配内存:1.新生代:Eden空间,FromSurvivor空间,ToSurvivor空间 2.老年代 3.线程共享的堆内存还可能会划分出多个线程私有的分配缓冲区TLAB(ThreadLocalAllocationBuffer))

5. 方法区(线程共享,用于储存虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码:class文件保存的信息:类的版本、字段、方法、接口和class的常量池(用于存放编译器生成的各种字面量和符号引用)等,运行时常量池:对于class文件的常量内容,在类被加载时进入方法区的运行时常量池)

6. 直接内存(JDK的NIO的操作,引入了基于通道与缓冲区的IO防辐射,可以使用Native函数库直接分配堆外内存,通过DriectByteBuffer对象作为制片内存的引用进行操作,避免Java堆和Native堆的数据来回拷贝)

对象的创建

对类的初始化和加载

创建对象方式:内存绝对规整->指针碰撞(Compact回收算法的分配方式),内存不规整->空闲列表(CMS的Mark-Sweep回收算法的分配方式)

分配对象的时候保证同步:1. CAS+失败重试 2.TLAB(ThreadLocalAllocationBuffer):本地线程缓存

对象内存布局:头信息(header),实例数据,填充对齐

对象的访问定位:

使用句柄:本地变量表->句柄池(堆,到对象实例的指针+到对象类型的指针)->对象实例数据(堆)+对象类型数据(方法区)

使用直接指针:本地变量表->对象实例数据(包含对象类型的指针)->对象类型数据(方法区)

区别:

句柄稳定,只需修改句柄指针而不用修改实例数据

直接访问速度快,只需一次访问内存

垃圾回收

垃圾回收动作何时执行?

当年轻代内存满时,会引发一次普通GC,该GC仅回收年轻代。需要强调的是,年轻代满是指Eden代满,Survivor满不会引发GC

当年老代满时会引发Full GC,Full GC将会同时回收年轻代、年老代

当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载

何时会抛出OutOfMemoryException

并不是内存被耗空的时候才抛出,JVM98%的时间都花费在内存回收,每次回收的内存小于2%

更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC

更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: