JVM内存管理剖析

JVM是什么

java虚拟机,为什么需要虚拟机呢?
由于在不同的操作系统,需要不同的编译。为了适配不同的操作系统,用虚拟机来统一适配编程。

缺点:效率低。不同直接使用操作系统,而需要再次编译才可以。

分类:HotspotVm J9VM ZingVM

JVM的执行流程:将.java文件—编译成.class文件—运行在JVM中 --操作系统中
java,kotlin,Groovy等其他语言都可以编程成.class文件

JVM的内部结构

class文件经过 ----类加载器 进入JVM中
线程共享:堆,方法区
线程独享:java栈,本地方法栈,程序计数器

堆:存放对象的地方(最大内存)
方法区:类信息,常量池,静态变量,编译好的class
java栈:局部变量,方法出口,正在执行的方法内存模型
本地方法栈:本地方法 native–本地库
程序计数器:记录线程运行到的代码行

java栈

(字节码) 栈帧:局部变量,操作数栈,动态库接,返回地址,帧数据区
每一行代码都是一个栈,先赋值运算,入栈操作,得到结果,返回即出栈操作。

一个线程对应一个JVM栈
每调用一次java方法会得到方法局部变量和操作数栈的大小,并根据此分配栈内存。
栈帧在栈顶才是有效的。(当前栈)

类加载与对象创建

类加载

类的生命周期:加载—链接—初始化—使用 --销毁

加载:将java文件编译成.class文件
链接:分为验证,准备,解析
验证:判断字节码文件是否合格(格式是否正确)
准备:静态字段分配字段,并用默认值初始化。
解析:虚拟机常量池内符号引用替换成直接引用(多态机制,编译时转化成运行时)
初始化:类类变量初始化,构造方法和给属性变量赋值。

对象创建(类的实例化)

判断对象对应类是否加载,链接和初始化等一系列操作
为对象分配内存(是否规整。指针碰撞和空闲列表)
处理类安全问题(多线程中找到了相同的内存地址)(CAS算法和本地线程分配缓冲区)
初始化并分配内存空间(初始化零值)
设置对象的对象头(hasCode,所属类,GC分代等信息存在对象头中)
执行init方法进行初始化(构造方法,初始化成员变量等)

对象在JVM的生命周期

创建阶段
应用阶段
不可见阶段 (没有强引用)
不可达阶段 (没强引用,被JVM标记)
收集阶段 (正在收集,通过finalize方法可以监听)
终结阶段

回收算法

对象回收时机

判断一个对象是否可以回收,看当前使用的是否可达当前对象。(对象被引用到)

GC roots: 静态变量 线程栈变量 常量池 JNI 这些变量是否被引用。

一般时看线程栈变量中。

当前对象是否引用到GC roots中的变量。引用到,即可达。不能回收。

标记清除法

GC回收时,扫描对象,判断对象是否被GCroots引用,没被引用即标记。等下次GC到来时,将标记的清除掉。

缺点:内存碎片化问题。

标记整理法

为了解决内存碎片化问题,将标记的变量整理,合理化利用空间。

缺点:效率低。(问题:整理的时候,需要将对象挂起,再改变引用地址)(问题:整理时空间不够,需要二次复制)

复制算法

将内存空间一分为二,一边是使用空间(对象面),一边是空闲面。当GC来的是先标记,清除时,将存活的对象整理到空闲面,然后将对象面不可达对象清空。

缺点:内存消耗大(空间利用率低)效率高

问题:当如果要清除的对象很少时,需要复制的对象太多,而导致效率低。

三种算法比较

效率:复制>标记整理>标记清除
内存整齐度:复制=标记整理>标记清除
内存利用率:标记整理=标记清除>复制

分代回收机制

青年代:频繁创建,死亡率高(看情况,标记整理和标记清除)

老年代:对象稳定,死亡率低(复制算法)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值