JVM内存结构相关知识点

本文详细介绍了Java虚拟机(JVM)的运行机制,包括JVM内存结构、运行时数据区的各个区域如程序计数器、虚拟机栈、本地方法栈、Java堆和元空间的特性及作用。讲解了对象在堆内存中的分配策略,对象布局,以及垃圾回收的判断标准。此外,还探讨了堆内存溢出的情况及如何预防。
摘要由CSDN通过智能技术生成

2.1java代码到底是如何运行起来的

 

见图

2.2画一下整个JVM运行原理图

 

见图

2.3请介绍一下JVM的内存结构划分

 

见图

2.4JVM哪些区域是线程私有的,哪些区域是线程共享的?

1、堆、元空间(方法区)是线程共享的;

2、其他区域是线程私有的;

2.6 JVM运行时数据区程序计数器的特点及作用?

1、程序计数器是一块较小的内存空间,几乎可以忽略;

2、是当前线程所执行的字节码的行号指示器;

3、Java多线程执行时,每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响;

4、该区域是“线程私有”的内存,每个线程独立存储;

5、该区域不存在OutOfMemoryError;

6、无GC回收;

2.7 JVM运行时数据区虚拟机栈的特点及作用?

1、线程私有;

2、方法执行会创建栈帧,存储局部变量表等信息;

3、方法执行入虚拟机栈,方法执行完出虚拟机栈;(先进后出)

4、栈深度大于虚拟机所允许StackOverflowError;(一般出现在递归调用的时候)

5、栈需扩展而无法申请空间OutOfMemoryError(比较少见); hotspot虚拟机没有;

6、栈里面运行方法,存放方法的局部变量名,变量名所指向的值(常量值、对象值等)都存放到堆上的;

7、栈一般都不设置大小,栈所占的空间其实很小,可以通过-Xss1M进行设置,如果不设置默认为1M;

8、随线程而生,随线程而灭;

9、该区域不会有GC回收;

 

2.8 JVM运行时数据区本地方法栈的特点及作用?

1、与虚拟机栈基本类似;

2、区别在于本地方法栈为Native方法服务;

3、HotSpot虚拟机将虚拟机栈和本地方法栈合并;

4、有StackOverflowError和OutOfMemoryError (比较少见);

5、随线程而生,随线程而灭;

6、GC不会回收该区域;

2.9 JVM运行时数据区Java堆的特点及作用?

1、线程共享的一块区域;

2、虚拟机启动时创建;

3、虚拟机所管理的内存中最大的一块区域;

4、存放所有实例对象和数组;

5、GC垃圾收集器的主要管理区域;

6、可分为新生代、老年代;

 

见图

7、新生代更细化可分为Eden、From Survivor、To Survivor,Eden:Survivor = 8:1:1

8、可通过-Xmx、-Xms调节堆大小;

9、无法再扩展java.lang.OutOfMemoryError: Java heap space

10、如果从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB),以提升对象分配时的效率;

2.10 JVM中对象如何在堆内存分配?

1、指针碰撞(Bump The Pointer) :内存规整的情况下;

2、空闲列表(Free List) :内存不规整的情况下;

选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有空间压缩整理(Compact)的能力决定;

因此,当使用Serial、ParNew等带压缩整理过程的收集器时,系统采用的分配算法是指针碰撞,既简单又高效;

而当使用CMS这种基于清除(Sweep)算法的收集器时,理论上就只能采用较为复杂的空闲列表来分配内存;

3、本地线程分配缓冲r(Thread Local Allocation Buffer,TLAB)︰对象创建在虚拟机中频繁发生,即使仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现

正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况;

那么解决方案有两种:

(1)同步锁定,JVM是采用CAS配上失败重试的方式保证更新操作的原子性;

(2)线程隔离,把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB),

哪个线程要分配内存,就在哪个线程的本地缓冲区中分配,只有本地缓冲区用完了,分配新的缓存区时才需要同步锁定,虚拟机是否使用TLAB,可以通过-XX: +/-UseTLAB参数来设定;如果是0的话就自动分配

2.11 JVM堆内存中的对象布局?

 

在HotSpot虚拟机中,一个对象的存储结构分为3块区域:对象头(Header)、实例数据

(Instance Data)和对齐填充(Padding);

对象头(Header):包含两部分,第一部分用于存储对象自身的运行时数据,

如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,32位虚拟机占32 bit,

64位虚拟机占64 bit,官方称为‘Mark Word';

第二部分是类型指针,即对象指向它的类的元数据指针,虚拟机通过这个指针确定这个对象是

哪个类的实例,另外,如果是Java数组,对象头中还必须有一块用于记录数组长度的数据,

因为普通对象可以通过Java 对象元数据确定大小,而数组对象不可以;

实例数据(Instance Data):程序代码中所定义的各种成员变量类型的字段内容(包含父类继承

下来的和子类中定义的);

对齐填充(Padding):不是必然需要,主要是占位,保证对象大小是某个字节的整数倍,

HotSpot虚拟机,任何对象的大小都是8字节的整数倍;

2.12JVM什么情况下会发生堆内存溢出?

Java堆中用于储存对象,只要不断地创建对象,并且保持GC Roots到对象之间有可达路径来避免垃圾回收机制清理这些对象,那么随着对象数量的增加,总容量达到最大堆的容量限制后就会产生内存溢出;

MAT工具分析xxx.hprof 文件,排查溢出的原因;

-Xms3072M

-Xmx3072M

-XX:-UseCompressedclassPointers

-XX:Metaspacesize=256M

-XX:MaxMetaspacesize=256M

-XX:SurvivorRatio=8

-XX:MaxTenuringThreshold=5

-XX:PretenuresizeThreshold=1M

-XX:+PrintGCDetails

-XX:+PrintGCDatestamps

-Xloggc:d: /dev/gc.log

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=d:/dev/heapdump.hprof

2.13 JVM如何判断对象可以被回收?

在JVM堆里面存放着所有的Java对象,垃圾收集器在对堆进行回收前,首先要确定这些对象之中哪些还“存活”着,哪些已经“死去”;

Java通过可达性分析(Reachability Analysis)算法来判定对象是否存活的;

该算法的基本思路:通过一系列称为“GC Roots”的根对象作为起始节点,从这些节点开始,

根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连(也称为不可达),则证明此对象是不可能再被使用的对象,就可以被垃圾回收器回收;

 

见图

对象object 5、object 6、object7虽然互有关联,但是它们到GKOOts定个可H的,凶此

它们将会被判定为可回收的对象;

哪些对象可以作为GC Roots呢?

1、在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等所引用的对象;

2、方法区/元空间中的类静态属性引用的对象;

3、方法区/元空间中的常量引用的对象;

4、在本地方法栈中JNI(即通常所说的Native方法)引用的对象;

5、Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器;

6、所有被同步锁(synchronized关键字)持有的对象;

7、反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等;

8、其他可能临时性加入的对象;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值