详解JVM系列之内存模型


Posted in Javascript onJune 10, 2021

1. 内存模型和运行时数据区

这一章学习java虚拟机内存模型(Java Virtual machine menory model),可以这样理解,jvm运行时数据库是一种规范,而JVM内存模型是对改规范的实现

详解JVM系列之内存模型

java虚拟机重点存储数据的是堆和方法区,所以本章节也重点从这两个方面进行比较详细描述。堆和方法区是内存共享的,而java虚拟机栈、Native方法栈、程序计数器是线程私有的

详解JVM系列之内存模型

2、思维导图和图例

详解JVM系列之内存模型

一个是非堆区(方法区),方法区也一般被称之为“永久代”。另外一个是堆区,分为young区和old区,young区又分为两个部分,一个是Eden区,一个是Survivor区(S0+S1),S0区也可以称之From区,S1也可以称之为To区

详解JVM系列之内存模型

3、对象向JVM申请空间

详解JVM系列之内存模型

4、为什么需要Survivor区?

为什么需要Survivor区?只有Eden不行吗?

假设不设计出Survivor区,Eden区进行一次MinorGC,对象就直接被送到Old区,这样一来Old区很快就被填满,Old区一满,就会进行FullGC(Old区会进行MajorGC,一般伴随着MinorGC),FullGC是很耗时的,所以设计出Survivor区的目的是减少对象被送到Old区,有一个过渡的Survivor区

补充:Minor GC:新生代
Major GC:老年代
Full GC:新生代+老年代
Eden:S1:S2是8:1:1

5、为什么需要两个Survivor区?

需要两个Survivor区的目的是为了避免内存碎片化。为什么这么说?
假设只设计出一个Survivor区,一旦Eden区满了,就会进行Minor GC,Eden区存活的对象就会被移动到Survivor区,等下一次Eden区满时候,问题就来了,进行MinorGC就将Eden区对象硬放到Survivor区,这样就导致了对象所占的内存是不连续的

6、例子进行验证

堆内存溢出

import lombok.Data;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class HeapController {

    List<Foo> list = new ArrayList<Foo>();
    @GetMapping(value = {"heap"})
    public String heapTest() {
        while (true) {
            list.add(new Foo());
        }
    }


    @Data
    class Foo {
        String str;
    }
}

访问接口,出现内存溢出;

java.lang.OutOfMemoryError: Java heap space

...

可以设置参数:比如-Xms64M -Xmx512M

方法区内存溢出

使用asm,maven配置:

<dependency>
  <groupId>asm</groupId>
  <artifactId>asm</artifactId>
  <version>3.3.1</version>
</dependency>

编写代码,向方法区中添加Class的信息,注意,电脑性能不够好,不要执行此代码,很容易,造成电脑重启,太吃内存,也可以调小循环次数

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.ArrayList;
import java.util.List;

public class MyMetaspace extends ClassLoader {

  public static List<Class<?>> createClasses() {
    List<Class<?>> classes = new ArrayList<Class<?>>();
    for (int i = 0; i < 10000000; ++i) {
      ClassWriter cw = new ClassWriter(0);
      cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null,
              "java/lang/Object", null);
      MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
              "()V", null, null);
      mw.visitVarInsn(Opcodes.ALOAD, 0);
      mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
              "<init>", "()V");
      mw.visitInsn(Opcodes.RETURN);
      mw.visitMaxs(1, 1);
      mw.visitEnd();
      MyMetaspace test = new MyMetaspace();
      byte[] code = cw.toByteArray();
      Class<?> exampleClass = test.defineClass("Class" + i, code, 0,
              code.length);
      classes.add(exampleClass);
    }
    return classes;
  }
}

方法区测试接口:

import com.example.jvm.jvmexceptionexample.asm.MyMetaspace;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class NonHeapController {

    List<Class<?>> list = new ArrayList<Class<?>>();

    @GetMapping(value = {"/noheap"})
    public String noheap() {
        while (true) {
            list.addAll(MyMetaspace.createClasses());
        }
    }

}

java.lang.OutOfMemoryError: Metaspace

at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.5_54]

处理方法,设置Metaspace的大小,比如-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=512M

Java虚拟机栈

在前面学习,java虚拟机栈是通过栈帧方式存储,一个方法对应一个栈帧,按照队列模式进栈,所以要测试程序导致java虚拟机栈出现问题,可以通过递归方法方式进行测试:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class StackController {

    public static long count = 0;

    public static void add(long i) {
        count ++ ;
        add(i);
    }

    @GetMapping(value = {"stack"})
    public void stack() {
        add(1);
    }

}

StackOverflow,栈溢出异常:

java.lang.StackOverflowError: null

at com.example.jvm.jvmexceptionexample.controller.StackController.add(StackController.java:14) ~[classes/:na]

处理方法,设置-Xss256k:设置每个线程的堆栈大小。JDK 5以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K

以上就是详解JVM系列之内存模型的详细内容,更多关于JVM 内存模型 内存结构的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JavaScript的目的分析
Jan 05 Javascript
js动态创建、删除表格示例代码
Aug 07 Javascript
JS动画效果打开、关闭层的实现方法
May 09 Javascript
Angularjs整合微信UI(weui)
Mar 15 Javascript
JS 动态判断PC和手机浏览器实现代码
Sep 21 Javascript
浅析jQuery操作select控件的取值和设值
Dec 07 Javascript
vue实现文章内容过长点击阅读全文功能的实例
Dec 28 Javascript
简单两步使用node发送qq邮件的方法
Mar 01 Javascript
Angular value与ngValue区别详解
Nov 27 Javascript
vue单文件组件无法获取$refs的问题
Jun 24 Javascript
JavaScript动态生成表格的示例
Nov 02 Javascript
vue print.js打印支持Echarts图表操作
Nov 13 Javascript
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
一文搞懂redux在react中的初步用法
Jun 09 #Javascript
深入详解JS函数的柯里化
Jun 09 #Javascript
javascript canvas实现雨滴效果
用JS实现飞机大战小游戏
Jun 09 #Javascript
原生JS实现飞机大战小游戏
解决Vue+SpringBoot+Shiro跨域问题
Jun 09 #Vue.js
You might like
需要发散思维学习PHP
2009/06/29 PHP
Codeigniter控制器controller继承问题实例分析
2016/01/19 PHP
php 使用fopen函数创建、打开文件详解及实例代码
2016/09/24 PHP
YII框架中使用memcache的方法详解
2017/08/02 PHP
PHP反射原理与用法深入分析
2019/09/28 PHP
做网页的一些技巧
2007/02/01 Javascript
设置下载不需要倒计时cookie(倒计时代码)
2008/11/19 Javascript
dwr spring的集成实现代码
2009/03/22 Javascript
jquery表单验证使用插件formValidator
2012/11/10 Javascript
如何将JS的变量值传递给ASP变量
2012/12/10 Javascript
使用upstart把nodejs应用封装为系统服务实例
2014/06/01 NodeJs
js在IE与firefox的差异集锦
2014/11/11 Javascript
node.js中的fs.utimes方法使用说明
2014/12/15 Javascript
node.js中的fs.realpath方法使用说明
2014/12/16 Javascript
jQuery插件datepicker 日期连续选择
2015/06/12 Javascript
JS实现鼠标框选效果完整实例
2016/06/20 Javascript
WEB开发之注册页面验证码倒计时代码的实现
2016/12/15 Javascript
关于jQuery EasyUI 中刷新Tab选项卡后一个页面变形的解决方法
2017/03/02 Javascript
JS实现仿微信支付弹窗功能
2018/06/25 Javascript
微信小程序倒计时功能实例代码
2018/07/17 Javascript
[02:30]辉夜杯主赛事第二日胜者组半决赛 CDEC.Y赛后采访
2015/12/26 DOTA
Python中实现远程调用(RPC、RMI)简单例子
2014/04/28 Python
Python对数据库操作
2016/03/28 Python
在阿里云服务器上配置CentOS+Nginx+Python+Flask环境
2016/06/18 Python
Python判断中文字符串是否相等的实例
2018/07/06 Python
python实现高斯(Gauss)迭代法的例子
2019/11/20 Python
利用Python自动化操作AutoCAD的实现
2020/04/01 Python
TensorFlow2.X使用图片制作简单的数据集训练模型
2020/04/08 Python
Jupyter Notebook添加代码自动补全功能的实现
2021/01/07 Python
任意一块网页内容实现“活”的背景(目前火狐浏览器专有)
2014/05/07 HTML / CSS
介绍一下SQL注入攻击的种类和防范手段
2012/02/18 面试题
大学毕业生工作的自我评价
2013/10/01 职场文书
少先队学雷锋活动月总结
2014/03/09 职场文书
高中国旗下的演讲稿
2014/08/28 职场文书
教师节寄语2015
2015/03/23 职场文书
房屋买卖定金协议书
2016/03/21 职场文书