前面章节

JAVA-大白话探索JVM-类加载器(一)
JAVA-大白话探索JVM-类加载过程(二)

JVM运行时内存

通过之前的章节,我们知道.class类如何加载到内存中,如图红框


开始讲讲内存空间

先了解JVM的周期

  1. JVM在java程序执行时运行,结束时停止。
  2. 一个java程序对应开启一个JVM进程
  3. JVM的线程分为两种:守护线程和普通线程
    • 守护线程属于JVM自己使用的线程,如GC
    • 普通线程是java程序的线程

线程私有数据区

  • Java栈(VM Stack)
  • 本地方法栈(NM Stack)
  • 程序计数器及隐含寄存器(Program Counter Register)

    线程共享数据区

  • 方法区(Method Area)
  • Java堆(Heap)
  • 执行引擎
  • 本地方法接口
  • 本地方法库

你会发现,这都是些什么?????。。。。。。呃

不着急,一步一步来

首先,就是你了,方法区(Method Area,线程共享)

  1. 类的结构信息和类静态变量都保存在方法区(这样说会不会很抽象,举个例,例如运行时常量池,成员变量和方法数据,构造函数和普通函数的字节码内容,还包括一些在类、实例、接口初始化时用到的特殊方法。开发人员在程序中通过Class对象中的getName、isInstance等方法获取信息时,这些数据都来自方法区。)
  2. 程序中的所有线程共享一个方法区,简称全局共享
  3. 对于HotSpot虚拟机,方法区对应为永久代(Permanent Generation),但本质上,两者并不等价,仅仅是因为HotSpot虚拟机的设计团队是用永久代来实现方法区而已,对于其他的虚拟机(JRockit、J9)来说,是不存在永久代这一概念的。
  4. 使用永久代来实现方法区并不是一个好注意,由于方法区会存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等,在某些场景下非常容易出现永久代内存溢出。如Spring、Hibernate等框架在对类进行增强时,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载入内存。在JSP页面较多的情况下,也会出现同样的问题。
  5. 在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
  6. 还有一点需要说明的是,在JDK1.6中,方法区虽然被称为永久代,但并不意味着这些对象真的能够永久存在了,JVM的内存回收机制,仍然会对这一块区域进行扫描,即使回收这部分内存的条件相当苛刻。

呃。。。。。。。有点多,慢慢吸收,这方法区也需要好好琢磨琢磨,一不小心溢出就麻烦了。

其次,Java堆(Heap,线程共享)

  1. Java堆是JVM所管理的最大一块内存,所有线程共享这块内存区域,几乎所有的对象实例都在这里分配内存,因此,它也是垃圾收集器管理的主要区域。
  2. 从内存回收的角度来看,由于现在的收集器基本都采用分代收集算法,所以Java堆又可以细分成:新生代和老年代,新生代里面有分为:Eden空间、From Survivor空间、To Survivor空间。
  3. 有一点需要注意:Java堆空间只是在逻辑上是连续的,在物理上并不一定是连续的内存空间。
  4. 默认情况下,新生代中Eden空间与Survivor空间的比例是8:1,可以使用参数-XX:SurvivorRatio对其进行配置。大多数情况下,新生对象在新生代Eden区中分配,当Eden区没有足够的空间进行分配时,则触发一次Minor GC,将对象Copy到Survivor区,如果Survivor区没有足够的空间来容纳,则会通过分配担保机制提前转移到老年代去。
  5. 何为分配担保机制?在发送Minor GC前,JVM会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,如果是,那么可以确保Minor GC是安全的,如果不是,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果小于,直接进行Full GC,如果大于,将尝试着进行一次Minor GC,Minor GC失败才会触发Full GC。注:不同版本的JDK,流程略有不同。
  6. Survivor区作为Eden区和老年代的缓冲区域,常规情况下,在Survivor区的对象经过若干次垃圾回收仍然存活的话,才会被转移到老年代。JVM通过这种方式,将大部分命短的对象放在一起,将少数命长的对象放在一起,分别采取不同的回收策略。

    Java栈(Stack,线程私有)、本地方法栈

    Java栈

  7. java栈中只保存基础数据类型(四类八种)和自定义对象引用
  8. 存取类型:先进后出
  9. 栈内数据在超出其作用域将自动释放
  10. 每个栈是线程私有,它们的生命周期与线程相同。
  11. 每个线程建立一个操作栈,每个栈又包含若干个栈帧,每个栈帧对应每个方法调用
  12. 栈帧:
    • 局部变量区(方法内基本类型变量、变量对象指针)
    • 操作数栈区(存放方法执行过程中产生的结果)
    • 运行环境区(动态链接、方法返回相关信息、异常捕捉)

      本地方法栈

  13. 与JAVA栈类似
  14. 本地方法栈是在程序调用或JVM调用本地方法接口(Native)时候启用
  15. 本地方法非java语言编写,不受JVM管理
  16. HotSpot VM将本地方法栈和JVM栈合并了。

    程序计数器(线程私有)

    概念:在JVM概念模型里,字节码解释器工作时就说通过改变这个计算器的值来选取下一条需要执行的字节码指令。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

  17. Java虚拟机可以支持多条线程同时执行,多线程是通过线程轮流切换来获得CPU执行时间的,每条线程都会有独立的程序计数器
  18. 如果执行java方法,程序计数器记录JVM字节码指令的地址,如果执行 native,计数器为空(Underfined)
  19. 程序计数器这个内存区域在JVM规范中是唯一没有规定任何OutOfMemoryError的区域

运行时常量池(Runtime Constant Pool)

  1. 方法区的一部分,用于存放编译期间生成的各种字面量(int,short等等)和符号引用(对象符号引用Integer,String)
  2. 除了编译产生能存入,运行期间也能将新的常量放入池中(String.intern())
  3. 节省内存空间:常量池中如果有对应的字符串,那么则返回该对象的引用,从而不必再次创建一个新对象。
  4. 节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,==判断引用是否相等,也就可以判断实际值是否相等
  5. Byte、Short、Integer、Long、Character这5种包装类都默认创建了数值[-128 , 127]的缓存数据。当对这5个类型的数据不在这个区间内的时候,将会去创建新的对象,并且不会将这些新的对象放入常量池中。
  6. Oracle对Java 7中的常量池做了一个非常重要的改变 — 常量池被重新定位到堆中。这意味着你不再受限于单独的固定大小内存区域。所有字符串现在都位于堆中,与大多数其他普通对象一样,这使你可以在调整应用程序时仅管理堆大小。

完了······

先暂时这么多吧,以上是我个人针对JVM的总结,也方便大家快速理解跟巩固,有错误的地方望告知下,谢谢。

版权声明:本文为不会代码的小白原创文章,转载需添加小白地址 :https://www.ccode.live/bertonlee/list/12?from=art

JAVA-大白话探索JVM-运行时内存(三)的更多相关文章

  1. 【Java】关于JVM运行时内存空间、JVM垃圾回收机制

    参考的优秀文章 <深入理解Java虚拟机 JVM高级特性与最佳实线>(机械工业出版社) Java虚拟机的堆.栈.堆栈如何去理解? 聊聊JVM的年轻代 前言 本文是<深入理解Java虚 ...

  2. JVM 运行时内存结构

      1.JVM内存模型       JVM运行时内存=共享内存区+线程内存区 1).共享内存区       共享内存区=持久带+堆       持久带=方法区+其他       堆=Old Space ...

  3. JVM运行时内存结构

    原文转载自:http://my.oschina.net/sunchp/blog/369707 1.JVM内存模型 JVM运行时内存=共享内存区+线程内存区 1).共享内存区 共享内存区=持久带+堆 持 ...

  4. [转]JVM运行时内存结构

    [转]http://www.cnblogs.com/dolphin0520/p/3783345.html 目录[-] 1.为什么会有年轻代 2.年轻代中的GC 3.一个对象的这一辈子 4.有关年轻代的 ...

  5. Jvm运行时内存解析

    一.jvm的概念 在了解jvm的概念之前,我们先来了解java平台的逻辑结构,图片来自<深入java虚拟机> 从图中我们可以看到jdk包含了jre,java语言和java开发工具和Api, ...

  6. 基础篇:JVM运行时内存布局

    目录 1 JVM的内存区域布局 2 JVM五大数据区域介绍 3 JVM运行时内存布局和JMM内存模型区别 4 JMM内存模型交互操作 欢迎指正文中错误 关注公众号,一起交流 参考文章 1 JVM的内存 ...

  7. 详细了解JVM运行时内存

    详细了解JVM运行时内存 1.程序计数器 概念 程序计数器也叫作PC寄存器,是一块很小的内存区域,可以看做是当前线程执行的字节码的行号指示器.字节码的解释工作就是通过改变程序计数器里面的值来获得下一条 ...

  8. JVM运行时内存组成分为一些线程私

    JVM运行时内存组成分为一些线程私有的,其他的是线程共享的. 线程私有 程序计数器:当前线程所执行的字节码的行号指示器. Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧 ...

  9. JVM02——JVM运行时内存

    在上一篇文章中,我们介绍了 JVM 的内存区域,本文我们将继续围绕 JVM 展开话题,介绍 JVM 运行时内存.关注我的公众号「Java面典」了解更多 Java 相关知识点. Java 堆从 GC 的 ...

  10. Java Core - JVM运行时内存管理

    在读正文之前,阅读以下两篇博客学习并理解堆栈.作用域.本地方法的概念. 作用域:https://www.cnblogs.com/AlanLee/p/6627949.html 操作数栈:https:// ...

随机推荐

  1. 圆桌的项目Alpha冲刺(团队)

    (a) 项目课堂演示 (b) 10篇冲刺随笔 冲刺之一 冲刺之二 冲刺之三 冲刺之四 冲刺之五 冲刺之六 冲刺之七 冲刺之八 冲刺之⑨ 冲刺之十 (c) 1篇测试随笔 测试随笔 (d) 1篇冲刺总结随 ...

  2. intval()和int()

    int intval ( mixed $var [, int $base ] )    通过使用特定的进制转换(默认是十进制),参数base表示进制,只有当var是字符串时,base才会有意义,表示按 ...

  3. datatime

    /把一个日期字符串如“2007-2-28 10:18:30”转换为Date对象 var   strArray=str.split("   "); var   strDate=str ...

  4. codeforces742B

    Arpa’s obvious problem and Mehrdad’s terrible solution CodeForces - 742B There are some beautiful gi ...

  5. POJ3273-Monthly Expense-二分答案

    FJ对以后的每一天会花mi块钱,他想把这些天分成M个时段,然后每个时段的花费和最小. 二分答案,如果加上这天还没有达到mid,就加上它.之后看分成的时段是否大于M #include <cstdi ...

  6. codeforces 777C

    C.Alyona and Spreadsheet During the lesson small girl Alyona works with one famous spreadsheet compu ...

  7. virtualenv 模块

    作用 安装虚拟环境 下载组件 pip3 install virtualenv 使用 命令行创建使用 """ 创建虚拟环境 """ virtu ...

  8. 用树莓派改装电风扇及实现Android遥控

    最近天气很热,我租的房子又没有空调,基本上风扇一开就是一晚上,结果经常起床后发现口干舌燥的.我觉得这肯定是因为整晚吹风扇搞的,不管是不是,反正我觉得就是了.不开风扇吧,热!开风扇吧,早上起来不舒服,怎 ...

  9. 03 自学Aruba之2.4GHz及5GHz无线信道

    点击返回:自学Aruba之路点击返回:自学Aruba集锦 03 自学Aruba之2.4GHz及5GHz无线信道 1.  2.4GHz信道 在各国家授权使用的频段: 信道号 中心频率(GHz) 美国FC ...

  10. 自学Linux Shell3.6-文件查看命令file cat more less tail head

    点击返回 自学Linux命令行与Shell脚本之路 3.6-文件查看命令file cat more less tail head 1.参看文件类型file 该命令用来识别文件类型,也可用来辨别一些文件 ...