Java内存学习笔记(一)

本文详细介绍了Java内存模型的各个组成部分,包括程序计数器、虚拟机栈、本地方法栈、Java堆、方法区、运行时常量池及直接内存的功能与特性。此外还深入探讨了HotSpot虚拟机的对象创建过程及其在内存中的布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java内存

1.      程序计数器

a)      比较小,Java内存中唯一不会抛出OutOfMemoryError的区域;

b)      线程私有;

c)      用于指示当前线程所执行的字节码地址(行号);

2.      虚拟机栈

a)      描述了Java方法调用的内存模型:方法调用时会生成一个栈帧,包括了局部变量表,动态链接,操作数栈,方法调用出口;

b)      线程私有;

c)      在代码编译期就可以确定所占空间;

d)      通常说的栈内存就是特指虚拟机栈的局部变量表:基本类型变量,对象引用,returnAddress

e)      如果线程请求的栈深度大于虚拟机所允许的深度,会抛出StackOverflowError;如果虚拟机栈可以扩展,且扩展时无法申请到足够的内存,抛出OutOfMemoryError异常;

f)      HotSpot通过-Xss设置栈容量;

3.      本地方法栈

a)      与虚拟机栈类似,虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机使用到的Native方法服务,有的虚拟机将两者实现合二为一(Sun HotSpot);

b)      也会抛出StackOverflowErrorOutOfMemoryError异常;

4.      Java

a)      所有线程共享,Java内存最大的一块,虚拟机启动时创建;

b)      所有对象实例和数组内存的分配(随着技术发展,这也不绝对);

c)      是垃圾收集管理器的主要工作区域,也称为GC堆;

d)      从内存回收角度,现在基本虚拟机都采用分代收集算法,所以Java堆可以分为Old GenerationNew Generation,再细致点包括EdenFrom SurvivorTo Survivor等;

e)      从内存分配的角度,还可以划分多个线程私有的分配缓冲区(TLAB);

f)      可以在物理上处于不连续的空间,但逻辑上是连续的;

g)      基本按照可扩展来实现,通过-Xms(堆最小值)和-Xmx(堆最大值)控制;

h)      当内存无法再扩展时,抛出OutOfMemeoryError异常:java.lang.OutOfMemoryError: Java heap space

5.      方法区

a)      线程共享的区域,用于存放被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,也叫做Non-heap

b)      HotSpot用永久代来实现方法区,不过这种方法将逐步被取代,永久代有-XX:MaxPermSize上限;

c)      不需要连续的内存空间,也可以选择固定大小或可扩展,还可以选择不实现垃圾回收;

d)      会出现OutOfMemoryError异常;

e)      HotSpot通过-XX:PermSize-XX:MaxPermSize设置永久代大小;

6.      运行时常量池

a)      方法区的一部分;

b)      编译期生成各种字面量和符号引用,以及运行期间生成的常量(stringintern方法);

c)      具备动态性,并不一定要求常量一定只有编译期才能产生;

d)      会出现OutOfMemoryError异常;

7.      直接内存

a)      可通过-XX:MaxDirectMemorySize指定,如果不指定则与-Xmx一样大小;

 

 

HotSpot对象创建

New一个对象时:

1.      首先检查指令的参数是否能在常量池定位到符号引用,并检查该符号引用对应的类是否被加载,否则执行类加载过程;

2.      为对象分配内存空间:由Java堆是否规整决定选择指针碰撞或空闲列表,堆是否规整由垃圾收集器是否带有压缩功能决定;

3.      为了保证内存分配时的线程安全,有两种手段:一种是进行同步处理,即CAS配上失败重试;另一种是TLAB

4.      分配的内存空间初始化;

5.      对对象进行必要设置,将信息放在对象头;

对象在内存中存储的布局包括:对象头,实例数据,和对齐填充。

对象头包括运行时数据(也叫Mark Word)和类型指针;

实例数据是对象真正存储的有效信息,这部分的存储顺序受虚拟机分配策略参数和字段定义顺序影响;

HotSpot要求对象其实地址必须是8字节的整数倍,因此需要对齐填充来补全。

 

对对象的访问定位,通过栈上的reference来操作堆上的具体对象,可以使用句柄或直接指针。

如果使用句柄,则需要划分句柄池,句柄中包含了对象实例数据指针和对象类型数据的指针,reference中存放的是稳定的句柄地址,不管对象是否被移动都不需修改;

直接指针访问,速度快,节省了一次指针定位开销,在HotSpot应用了该种手段;

 

 

是否可以这样理解:

1. 虚拟机启动时根据参数分配各部分内存,程序计数器,虚拟机栈和本地方法栈(-Xss),Java堆(-Xms,-Xmx),方法区(包括运行时常量池,-XX:PermSize,-XX:MaxPermSize),直接内存(-XX:MaxDirectMemorySize)等;

2. 有一个类,在编译时可以确定该类的局部变量(基本数据类型,对象引用等),并在虚拟机栈分配所需内存空间;

3. 线程启动时,程序计数器有一个程序字节码指令的地址;

4. 当新建一个类实例时,会在Java堆中分配内存,而对象引用是放在虚拟机栈的局部变量表中;

5. 虚拟机会加载类的类信息,常量,静态变量等到方法区,其中运行时常量池加载类的字面量和符号引用;

关于直接引用和符号引用:http://blog.youkuaiyun.com/kkdelta/article/details/17752097

转载于:https://my.oschina.net/sayitok/blog/215244

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值