JVM之内存池与内存模型

JVM内存模型

JVM内存模型其实就是JVM在启动的时候从操作系统内存中要了一块大内存,然后将这个大内存分成五个区域:方法区、堆区、虚拟机栈、本地方法栈、程序计数器。
图例:
在这里插入图片描述

方法区

  1. 永久代和元空间

     永久代:jdk8之前方法区的具体实现,直接存在堆区
     元空间:jdk8及以后方法区的具体实现,直接内存,os内存
    

    可以这么理解:方法区是一个规范,概念,类似java中的接口。而永久代和元空间是具体的实现类。
    类的元信息instanceKlass就是存储在元空间里的

  2. JVM为什么用元空间代替了永久代?
    1.gc算法
    我们知道堆区是存储对象的,而之前把像什么类信息,字段这些存再堆。gc做标记的时候就需要区分开那一块是那一块。而改成元信息之后,gc算法就比较好写了
    2.OOM
    类有时候动态生成,比如像cglib,很容易就OOM了
    3.硬件的发展
    之前是32bit,现在可以有64bit

  3. 元空间最大最小是多少?

     最大:  4294901760 =4095M
     最小:	21807104 =20.75M
    
  4. 元空间如何调优?
    -XX:MetaspaceSize
    -XX:MaxMetaspaceSize
    跟堆一样,最大最小调成一样(可以防止内存抖动)
    调成多少,物理内存的1/32
    visualVm、arthas调试工具

本地方法栈

java调用c、c++的动态链接库,运行里面的函数需要的栈

程序计数器

执行引擎的指针

虚拟机栈

一个虚拟机有多少个虚拟机栈?
一个线程一个
一个虚拟机栈有多少个栈帧?
方法调用个,一个方法一个

栈帧:

局部变量表

存储局部变量的表(LocalVariableTable)

操作数栈

是使用字节码指令对数据进行操作了,push,pop之类的,需要查看:字节码手册
在这里插入图片描述

动态链接
	指向方法对象的内存地址
返回地址,保存现场
这一步干了很多事,看这个代码
每个方法都都会生成一个栈帧,对把。我们执行到add()的时候
1. 生成add的栈帧
2. 在add方法的栈帧中保存main方法的字节码的下一行程序计数器
3. 将线程的局部表开始指针(main的)保存到add的栈帧中
4. 将线程的操作数栈开始指针(main的)保存到add的栈帧中
5. 将add的局部表开始指针赋值给线程的局部表指针
6. 将add的操作数栈开始指针赋值给线程的操作数栈的指针

在这里插入图片描述

堆区

最大大小:1/4实际内存大小
最小大小:1/32实际内存大小

大对象什么时候会进入老年代?
1.15次gc之后,自动进入老年代

为啥是15次?可以调成16次嘛?
	因为它占4bit,对应的二进制等于15.所以只能调小,不能调大

2.大对象
超过eden区的一半,直接进去老年代
eden的大小是动态调整的
3.空间担保
gc以后,Eden区剩下的对象还是比form区或to区都大,又不能丢弃,所以进去老年代
4.动态调整
gc之后,eden区和from区的对象,to区放不下,进入老年代

总结问题

1.虚拟机栈指向方法区
动态链接
2. 虚拟机指向堆区
对象的引用Test obj = new Test()
3. 方法区指向堆区
引用类型的静态属性
4. 堆区指向方法区
Klacc pointer,指向改对象的InstanceKalss实例
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值