前言

Java和C或者是C++相比较而言,最大的区别是C系列的程序员在编写代码的时候,总是要对程序中的变量进行释放内存的操作,所以在编写C或者是C++的程序员需要格外的谨慎,因为他们对程序的内存有着很高的权限,这样虽然是特点但是同时也是缺点,毕竟every coin has two sides。所以跟Java语言相比而言,Java把内存的管理直接交付给JVM,因为JVM的存在,Java程序员能够更关注业务的实现,而不需要对内存的管理过于关注。但是我们在编程的时候,有时候会出现OutOfMemoryError之类的错误,这就是JVM内存溢出的错误。这样如果我们对Java虚拟机对内存的管理,我们就不能很好的解决类似的问题,所以我们还是要对Java的内存管理要有一定的理解,对我们后期对Java代码调优也是有一定的帮助。

Java虚拟机内存模型

 
根据上图可以看出来JVM的运行时数据区域主要就是方法区,虚拟机栈,虚拟机堆内存,本地方法区和程序计数器。下面就来看看这些个内存区域都是用来存储哪些数据的。

Java虚拟机栈

方法区是线程私有的内存区域,声明周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型,每个方法执行的时候,虚拟机会以栈帧的形式压入到栈中,这里的栈也是一种先进后出的数据结构。栈帧通常是用来存储局部变量表,操作数栈,帧数据区等信息。每个方法的调用和结束都是入栈和出栈的操作。由于每次方法的调用都会生成对应的栈帧,栈帧会占用一定的栈空间,因此,如果栈帧的空间不足,函数的调用就无法进行下去,当请求的栈的深度大于最大的可用栈深度的时候,系统就会抛出StackOverflowError的溢出错误。 
局部变量表存放编译期可以知道的各种基本数据类型(boolean,byte,char,short,int,float,long,double),对象引用和returnAddress类型。其中64位长度的long和double类型的数据会占用2个slot局部变量空间,其余的都是一个slot。局部变量表所需要的内存空间在编译期间完成分配,运行期间不会改变局部变量表的大小。 
代码实现StackOverflowError的溢出错误

package com.jvm.method_region;public class MethodRegionTest {Integer count = 0;public void method1() { count ++; method1(); } public static void main(String[] args) { MethodRegionTest methodRegionTest = null; try { methodRegionTest = new MethodRegionTest(); methodRegionTest.method1(); }catch (Exception e) { // TODO: handle exception }finally { System.out.println("递归java栈的深度是 : " + methodRegionTest.count);

在运行的时候,修改JVM参数,通过修改-Xss128K可以改变虚拟机栈的大小,我第一次是128K第二次是256K,看执行的结果

递归java栈的深度是 : 994
Exception in thread "main" java.lang.StackOverflowError at java.lang.Integer.<init>(Unknown Source) at java.lang.Integer.valueOf(Unknown Source) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:8) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

第二次

递归java栈的深度是 : 2475
Exception in thread "main" java.lang.StackOverflowError at java.lang.Integer.<init>(Unknown Source) at java.lang.Integer.valueOf(Unknown Source) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:8) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9) at com.jvm.method_region.MethodRegionTest.method1(MethodRegionTest.java:9)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在eclipse改变JVM的参数操作 
 
<————————-这是分隔符————————————-> 

本地方法栈

本地方法栈和虚拟机栈类似,但是他们也是有区别的,区别就是虚拟机栈是调用java方法的时候,会把栈帧压入栈中,而本地方法栈是调用的native方法,native是由C++编写的。同时本地方法栈也会和虚拟机栈一样也是会爆出来StackOverflowError和OutOfMemoryError的错误。OutOfMemoryError的错误是在虚拟机的栈内存可以自动扩展的情况下,不停的将栈帧数据压入到栈中,以至于虚拟机不停的申请内存,最后导致内存的溢出,所以爆出来OutOfMemoryError错误。

虚拟机堆

Java Heap是Java虚拟机所管理的内存最大的一块,这一块的内存区域是所有线程共享的。此内存区域是用来存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。Java Heap还可以细分为新生代区和老年代区,而新生代区还可以分为eden区,from区和to区,from和to的大小是一样的。在绝大数的情况下,对象是先分配在eden区,在第一次垃圾回收后,如果对象还存活着,那么该对象就会进入到from区或者是to区,然后每经过一次垃圾回收,对象依然存活着,它的年纪就会增加1。当对象的年纪到达一定的条件后,该对象就会进入到老年tenured区。

程序计数器

Program Counter是每个线程的私有空间,Java虚拟机会为每一个线程创建PC寄存器,在任意时刻,一个线程总是在执行一个方法,正在执行的方法称为当前方法。如果当前方法不是本地方法,PC寄存器就会指向当前正在被执行的指令。如果当前方法是本地方法,那么PC寄存器的值就是undefined。

方法区

方法区也是线程共享的内存区域,用于保存系统的类信息,比如类的字段,方法,常量池等,方法区的大小决定了系统可以保存多少个类如果系统定义了太多的类,同样会导致方法区的溢出。在JDK1.6和JDK1.7中,方法区可以理解为永久区(Perm)。永久区可以使用参数-XX:PermSize和-XX:MaxPermSize指定,默认情况下,-XX:MaxPermSize为64MB。一个大的永久区可以保存更多的信息。如果系统中使用一些动态代理,那么就有可能在运行时生成大量的类。在JDK1.8中,永久区已经被彻底移除,用元数据区来代替。元数据区可以使用-XX:MaxMetaspaceSize指定,元数据区使用的系统的直接内存。如果不指定元数据的大小,程序会耗尽所有的内存。

package com.jvm.perm;import net.sf.cglib.beans.BeanGenerator;public class PermTest { class Perm{ String name; public String getName(www.bomaoyule.cn) { return name; } public void setName(String name) { this.name = name; } } public static void main(String[www.yingka178.com ] args) { try { for (int i = 0; i < 1000000; i++) { BeanGenerator generator = new BeanGenerator(www.078881.cn ); generator.setSuperclass(Perm.class); generator.addProperty("name", String.class); generator.create(www.chaoyueyule.com/); } } catch (Exception www.dongfan178.com e) www.mcyllpt.com/ { // TODO: handle exception

加了虚拟机参数-XX:+PrintGCDetails -XX:MaxMetaspaceSize=256k 
运行结果

Error occurred during initialization of VM
OutOfMemoryError: Metaspace

转载于:https://www.cnblogs.com/qwangxiao/p/9249586.html

JVM从入门到放弃——JVM内存模型相关推荐

  1. 【JVM】第四章 Java内存模型

    第四章 Java内存模型 文章目录 第四章 Java内存模型 一.物理机的并发问题 1.硬件的效率问题 2.缓存一致性问题 3.代码乱序执行优化问题 二.Java 内存模型 1.概念 2.Java 内 ...

  2. JVM知识(三):内存模型和可见性

    这篇文章我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况.来聊聊java线程对一个变量的更新怎么通知另一个线程,及volatile的作用和 ...

  3. JVM成神之路-Java内存模型(JMM)

    Java 内存模型基础 什么是 Java 内存模型(JMM-共享内存模型) 内存模型描述了程序中各个变量(实例域.静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量 ...

  4. JVM(一)组成及内存模型

    一.内存模型 JVM组成部分 首先通过类加载器(ClassLoader)会把 Java 代码转换成字节码 运行时数据区(Runtime Data Area)再把字节码加载到内存中,而字节码文件只是 J ...

  5. JVM——CPU缓存架构与Java 内存模型

    导航 一.CPU缓存架构与一致性协议 1.1 CPU缓存架构 1.2 缓存行与伪共享问题 1.3 MESI 缓存一致性协议 1.4 伪共享的解决办法 二.JMM Java 内存模型 2.1 JMM 简 ...

  6. JVM系列(三)— Java内存模型

    我们已经了解了Java虚拟机的运行时数据区,垃圾收集相关知识,接下来学习虚拟机非常重要的部分 这就是Java内存模型与线程(第12章),这一篇,将主要讲讲内存模型 了解Java内存模型之前,先了解下计 ...

  7. java实现初始化三角形数组_Java 数组、多维数组,动态、静态初始化,数组JVM内存模型分析...

    Java 数组.多维数组,动态.静态初始化,数组JVM内存模型分析 什么是数组 所谓数组,是具有相同数据类型的若干变量或者数据按照一定排序规则组合起来的一种数据存储格式.数组中的数据称为数组元素,我们 ...

  8. 全面理解java内存模型_深入理解Java内存模型(八)——总结

    处理器内存模型 顺序一致性内存模型是一个理论参考模型,JVM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JVM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...

  9. Java 内存模型(Java Memory Model,JMM)

    为了屏蔽各种硬件和操作系统的内存访问差异,JVM制定了一套JMM内存模型来实现同一套Java程序在不同平台上实现一样的运行效果.也就是一次编译到处运行跨平台的效果. JVM内存分配概念 JVM两个重要 ...

最新文章

  1. RouterOS连载3:架设PPPoE服务
  2. 简析.NET Core 以及与 .NET Framework的关系
  3. Qt 中使用dll文件的舒服用法 generateDocumentation()函数 乱码解决
  4. installEventFilter、eventFilter函数理解
  5. oracle unused 语法_oracle--set unused
  6. 简明Vim练级攻略(初学者)
  7. MUI组件:弹出层组件 - 案例篇
  8. AlexNet层级分析(涉及:卷积核操作下下层网络特征图size计算;对通道和卷积核尺寸及通道前层feature map和卷积核的运算关系的解释)
  9. python 拆分list,按照对应位置重组
  10. 一篇关于实体链接的小综述
  11. 2018leetcode算法面试题汇总部分解答
  12. 使用谷歌浏览器出现插件未就绪以及CLodop云打印服务(localhost本地)未安装启动!请下载安装包!
  13. ccy测试dlx 模块化与全局变量
  14. 什么是晶振?晶振在电路中的作用是什么?
  15. vue-element-admin右侧内容数据量多时,el-menu侧边栏收缩/展开卡顿问题
  16. 百度世界大会吴恩达演讲视频和内容
  17. Linux里面的进程管理
  18. storm和vgj vgj_DOTA2:Team VGJ宣布解散,再见VGJ!
  19. vue.js毕业设计,基于vue.js前后端分离订座预约系统设计与实现(H5移动项目)
  20. 区块链主流开源技术体系介绍

热门文章

  1. python php ajax赔率,Ajax如何调用python脚本
  2. jekenis父子结构项目打包_全栈之DevOps系列 - 发布 Python 项目 开源/私有 包
  3. linux+mysql+导出备份_Linux系统MySQL备份的导入导出的具体分析
  4. ZXing生成二维码
  5. 深度残差网络_注意力机制+软阈值化=深度残差收缩网络
  6. esp mounter pro_对比 | 以大欺小?剑指宋Pro和哈弗H6,欧尚X7的黑马潜质从何而来?...
  7. 震惊!printf 与scanf 不可告人的秘密
  8. java 06_JAVA06 数组
  9. c向文件中插入数据_如何把数据写入顺序文件中,VBA代码中Write#语句的利用
  10. python 如何匹配列表中某个单词_Python中部分指定单词的最佳匹配项