【java】jvm内存模型全面解析_哔哩哔哩_bilibili
白话解释:java内存模型即JMM,是java虚拟机的一种规范,定义了多线程环境下共享变量的访问规则以及不同线程之间如何通过内存进行交互。
jvm内存空间
jvm的内存空间主要有5个部分:堆、栈、本地方法栈、方法区(元空间)、程序计数器

私有与共享:
线程私有:栈、本地方法栈、程序计数器
线程共享:堆、方法区域
各个区的作用:
堆内存
存放对象的实例,所有线程共享,不会被JVM自动回收,要由GC来回收。
程序中所有的引用类型最后都会指向这里找到对象的实例(这里涉及到java对象的组成,每个对象都有一个对象头,存放对象的地址)。
- 堆里面区分:新生代+老年代;
- 新生代、老年代比例,默认1:1
- 新生代:Eden+Survivor0+Survivor1(Eden区和Survivor区比例=8:1:1)
- Eden:对象刚开始被分配的位置,当我们new对象时,就会在这里分配一段内存;
- Survivor区:0和1这两个区域都是用来存放Eden区中在本次GC过程中仍然存活的对象(还在被其它线程引用),它们2个是交替工作的。简略举例说明:
- 当Eden区第一次快满时,触发第一次垃圾回收,GCRoot会采用复制算法将仍然存活的对象从【Eden和Survivor1】复制一份到【Survivor0】中,之后GcRoot会将Eden和Survivor1全部回收。这就是所谓的YoungGC
- 当Eden区第二次快满时,触发第二次垃圾回收,GCRoot会采用复制算法将仍然存活的对象从【Eden和Survivor0】复制一份到【Survivor1】中,之后GcRoot会将Eden和Survivor0全部回收。
- YoungGC就是重复以上2步,可以充分利用内存
栈
存放线程执行时的上下文,每个线程都有独立的上下文,线程任务执行完成之后,所有内存空间都会被清空释放
例如:局部变量、操作数栈、方法出口等。(栈里面存的是地址,最终都会指向堆里面的对象)
本地方法栈
用来管理本地方法的调用,里面没有我们写的代码逻辑,由native关键词修饰。是由c++编写的,用来和操作系统实现底层指令交互。
比如:线程的start()方法,最后会调用一个本地方法:start0()。这个start0()就是被native修饰,具体逻辑是由c++实现的
方法区(jdk8之后改名:元空间)
用于存放已被虚拟机加载的类信息,常量,静态变量等数据。
程序计数器
是一块很小的内存空间,主要用来记录各个线程执行的字节码地址。例如:分支、循环、线程恢复等都依赖于计数器。
总结:
jvm内存空间的回收分为自动回收和GC回收;
栈的内存释放有JVM控制,堆的内存释放由GC守护线程来控制。关于GC守护线程的参数配置,在我们启动java程序时,可以通过一系列参数来设置。
下面是一段jdk8及之前版本的jvm启动参数,可以根据服务器配置自己修改
-XX:+UseG1GC \ # 使用垃圾回收器:G1
-XX:MaxGCPauseMillis=200 \ # 目标停顿时间,等的越久回收的内存空间越多
-XX:InitiatingHeapOccupancyPercent=45 \ # 堆占用45%就开始标记周期,触发GC,能降低Full GC风险
-XX:ParallelGCThreads=2 \ # 并行GC线程数,避免占用过多CPU(4核可选2~3)
-XX:ConcGCThreads=1 \ # 并发GC线程,单线程
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/app/java.hprof \
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:${GC_LOG_FILE} \ #打印gc详情到指定文件路径
1422

被折叠的 条评论
为什么被折叠?



