JAVA-大白话探索JVM-运行时内存(三)
前面章节
JAVA-大白话探索JVM-类加载器(一)
JAVA-大白话探索JVM-类加载过程(二)
JVM运行时内存
通过之前的章节,我们知道.class类如何加载到内存中,如图红框
开始讲讲内存空间
先了解JVM的周期
- JVM在java程序执行时运行,结束时停止。
- 一个java程序对应开启一个JVM进程
- JVM的线程分为两种:守护线程和普通线程
- 守护线程属于JVM自己使用的线程,如GC
- 普通线程是java程序的线程
线程私有数据区
- Java栈(VM Stack)
- 本地方法栈(NM Stack)
程序计数器及隐含寄存器(Program Counter Register)
线程共享数据区
- 方法区(Method Area)
- Java堆(Heap)
- 执行引擎
- 本地方法接口
本地方法库
你会发现,这都是些什么?????。。。。。。呃
不着急,一步一步来
首先,就是你了,方法区(Method Area,线程共享)
- 类的结构信息和类静态变量都保存在方法区(这样说会不会很抽象,举个例,例如运行时常量池,成员变量和方法数据,构造函数和普通函数的字节码内容,还包括一些在类、实例、接口初始化时用到的特殊方法。开发人员在程序中通过Class对象中的getName、isInstance等方法获取信息时,这些数据都来自方法区。)
- 程序中的所有线程共享一个方法区,简称全局共享
- 对于HotSpot虚拟机,方法区对应为永久代(Permanent Generation),但本质上,两者并不等价,仅仅是因为HotSpot虚拟机的设计团队是用永久代来实现方法区而已,对于其他的虚拟机(JRockit、J9)来说,是不存在永久代这一概念的。
- 使用永久代来实现方法区并不是一个好注意,由于方法区会存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等,在某些场景下非常容易出现永久代内存溢出。如Spring、Hibernate等框架在对类进行增强时,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载入内存。在JSP页面较多的情况下,也会出现同样的问题。
- 在JDK1.8下并没有出现我们期望的永久代内存溢出错误,而是Metaspace内存溢出错误。这是因为Java团队从JDK1.7开始就逐渐移除了永久代,到JDK1.8时,永久代已经被Metaspace取代,因此在JDK1.8并没有出现我们期望的永久代内存溢出错误。在JDK1.8中,JVM参数-XX:PermSize和-XX:MaxPermSize已经失效,取而代之的是-XX:MetaspaceSize和XX:MaxMetaspaceSize。注意:Metaspace已经不再使用堆空间,转而使用Native Memory
- 还有一点需要说明的是,在JDK1.6中,方法区虽然被称为永久代,但并不意味着这些对象真的能够永久存在了,JVM的内存回收机制,仍然会对这一块区域进行扫描,即使回收这部分内存的条件相当苛刻。
呃。。。。。。。有点多,慢慢吸收,这方法区也需要好好琢磨琢磨,一不小心溢出就麻烦了。
其次,Java堆(Heap,线程共享)
- Java堆是JVM所管理的最大一块内存,所有线程共享这块内存区域,几乎所有的对象实例都在这里分配内存,因此,它也是垃圾收集器管理的主要区域。
- 从内存回收的角度来看,由于现在的收集器基本都采用分代收集算法,所以Java堆又可以细分成:新生代和老年代,新生代里面有分为:Eden空间、From Survivor空间、To Survivor空间。
- 有一点需要注意:Java堆空间只是在逻辑上是连续的,在物理上并不一定是连续的内存空间。
- 默认情况下,新生代中Eden空间与Survivor空间的比例是8:1,可以使用参数-XX:SurvivorRatio对其进行配置。大多数情况下,新生对象在新生代Eden区中分配,当Eden区没有足够的空间进行分配时,则触发一次Minor GC,将对象Copy到Survivor区,如果Survivor区没有足够的空间来容纳,则会通过分配担保机制提前转移到老年代去。
- 何为分配担保机制?在发送Minor GC前,JVM会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果是,那么可以确保Minor GC是安全的,如果不是,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果小于,直接进行Full GC,如果大于,将尝试着进行一次Minor GC,Minor GC失败才会触发Full GC。注:不同版本的JDK,流程略有不同。
Survivor区作为Eden区和老年代的缓冲区域,常规情况下,在Survivor区的对象经过若干次垃圾回收仍然存活的话,才会被转移到老年代。JVM通过这种方式,将大部分命短的对象放在一起,将少数命长的对象放在一起,分别采取不同的回收策略。
Java栈(Stack,线程私有)、本地方法栈
Java栈
- java栈中只保存基础数据类型(四类八种)和自定义对象引用
- 存取类型:先进后出
- 栈内数据在超出其作用域将自动释放
- 每个栈是线程私有,它们的生命周期与线程相同。
- 每个线程建立一个操作栈,每个栈又包含若干个栈帧,每个栈帧对应每个方法调用
- 栈帧:
- 局部变量区(方法内基本类型变量、变量对象指针)
- 操作数栈区(存放方法执行过程中产生的结果)
运行环境区(动态链接、方法返回相关信息、异常捕捉)
本地方法栈
- 与JAVA栈类似
- 本地方法栈是在程序调用或JVM调用本地方法接口(Native)时候启用
- 本地方法非java语言编写,不受JVM管理
HotSpot VM将本地方法栈和JVM栈合并了。
程序计数器(线程私有)
概念:在JVM概念模型里,字节码解释器工作时就说通过改变这个计算器的值来选取下一条需要执行的字节码指令。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
- Java虚拟机可以支持多条线程同时执行,多线程是通过线程轮流切换来获得CPU执行时间的,每条线程都会有独立的程序计数器
- 如果执行java方法,程序计数器记录JVM字节码指令的地址,如果执行 native,计数器为空(Underfined)
程序计数器这个内存区域在JVM规范中是唯一没有规定任何OutOfMemoryError的区域
运行时常量池(Runtime Constant Pool)
- 方法区的一部分,用于存放编译期间生成的各种字面量(int,short等等)和符号引用(对象符号引用Integer,String)
- 除了编译产生能存入,运行期间也能将新的常量放入池中(String.intern())
- 节省内存空间:常量池中如果有对应的字符串,那么则返回该对象的引用,从而不必再次创建一个新对象。
- 节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,==判断引用是否相等,也就可以判断实际值是否相等
- Byte、Short、Integer、Long、Character这5种包装类都默认创建了数值[-128 , 127]的缓存数据。当对这5个类型的数据不在这个区间内的时候,将会去创建新的对象,并且不会将这些新的对象放入常量池中。
- Oracle对Java 7中的常量池做了一个非常重要的改变 — 常量池被重新定位到堆中。这意味着你不再受限于单独的固定大小内存区域。所有字符串现在都位于堆中,与大多数其他普通对象一样,这使你可以在调整应用程序时仅管理堆大小。
完了······
先暂时这么多吧,以上是我个人针对JVM的总结,也方便大家快速理解跟巩固,有错误的地方望告知下,谢谢。
版权声明:本文为不会代码的小白原创文章,转载需添加小白地址 :https://www.ccode.live/bertonlee/list/12?from=art
JAVA-大白话探索JVM-运行时内存(三)的更多相关文章
- 【Java】关于JVM运行时内存空间、JVM垃圾回收机制
参考的优秀文章 <深入理解Java虚拟机 JVM高级特性与最佳实线>(机械工业出版社) Java虚拟机的堆.栈.堆栈如何去理解? 聊聊JVM的年轻代 前言 本文是<深入理解Java虚 ...
- JVM 运行时内存结构
1.JVM内存模型 JVM运行时内存=共享内存区+线程内存区 1).共享内存区 共享内存区=持久带+堆 持久带=方法区+其他 堆=Old Space ...
- JVM运行时内存结构
原文转载自:http://my.oschina.net/sunchp/blog/369707 1.JVM内存模型 JVM运行时内存=共享内存区+线程内存区 1).共享内存区 共享内存区=持久带+堆 持 ...
- [转]JVM运行时内存结构
[转]http://www.cnblogs.com/dolphin0520/p/3783345.html 目录[-] 1.为什么会有年轻代 2.年轻代中的GC 3.一个对象的这一辈子 4.有关年轻代的 ...
- Jvm运行时内存解析
一.jvm的概念 在了解jvm的概念之前,我们先来了解java平台的逻辑结构,图片来自<深入java虚拟机> 从图中我们可以看到jdk包含了jre,java语言和java开发工具和Api, ...
- 基础篇:JVM运行时内存布局
目录 1 JVM的内存区域布局 2 JVM五大数据区域介绍 3 JVM运行时内存布局和JMM内存模型区别 4 JMM内存模型交互操作 欢迎指正文中错误 关注公众号,一起交流 参考文章 1 JVM的内存 ...
- 详细了解JVM运行时内存
详细了解JVM运行时内存 1.程序计数器 概念 程序计数器也叫作PC寄存器,是一块很小的内存区域,可以看做是当前线程执行的字节码的行号指示器.字节码的解释工作就是通过改变程序计数器里面的值来获得下一条 ...
- JVM运行时内存组成分为一些线程私
JVM运行时内存组成分为一些线程私有的,其他的是线程共享的. 线程私有 程序计数器:当前线程所执行的字节码的行号指示器. Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧 ...
- JVM02——JVM运行时内存
在上一篇文章中,我们介绍了 JVM 的内存区域,本文我们将继续围绕 JVM 展开话题,介绍 JVM 运行时内存.关注我的公众号「Java面典」了解更多 Java 相关知识点. Java 堆从 GC 的 ...
- Java Core - JVM运行时内存管理
在读正文之前,阅读以下两篇博客学习并理解堆栈.作用域.本地方法的概念. 作用域:https://www.cnblogs.com/AlanLee/p/6627949.html 操作数栈:https:// ...
随机推荐
- Vue 的语法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Python装饰器的深入理解
装饰器 #装饰器:本质上是函数,(装饰其他函数)就是为其他函数添加附加功能 #原则: 1.不能修改被装饰的函数的源代码 # 2.不能修改被装饰的函数的调用方式 #实现装饰器知识储备 #1.函数即变量 ...
- 捕捉JDialog的关闭事件
捕捉JDialog的关闭事件 http://xxqn.iteye.com/blog/431190 public class EditJDialog extends javax.swing.JDialo ...
- Markdown 文件转化为work文档
1. 电脑安装pandoc 链接:https://pan.baidu.com/s/12H5wLO0JWph5TjrbeJI6mg 密码:ssgs 下载安装包解压即可用.记得配置系统环境变量 2.命令行 ...
- Dictionary字典
泛型,键值对 Dictionary<int,string> dic=new Dictionary<int,string>(); dic.Add(,"张三") ...
- BZOJ1115[POI2009]石子游戏——阶梯Nim游戏
题目描述 有N堆石子,除了第一堆外,每堆石子个数都不少于前一堆的石子个数.两人轮流操作每次操作可以从一堆石子中移走任意多石子,但是要保证操作后仍然满足初始时的条件谁没有石子可移时输掉游戏.问先手是否必 ...
- BZOJ4386[POI2015]Wycieczki——矩阵乘法+倍增
题目描述 给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种.将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点. 输入 第 ...
- java 获取 T.class
转载:http://www.hankcs.com/program/t-class.html @Test public void Test() throws Exception{ Foo<User ...
- IDEA如何刷新pom文件
被新手问到了“IDEA如何刷新pom文件?”这个问题,想来这是一个不好意思问的常犯的错误吧. 在IDEA中,修改了pom.xml文件,添加了依赖以后,一般会弹出以下这个警告来. 点击[Import C ...
- 【BZOJ3668】【NOI2014】起床困难综合症(贪心)
[NOI2014]起床困难综合症(贪心) 题面 Description 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm 一直坚 ...