详解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 相关文章推荐
jQuery 动态酷效果实现总结
Dec 27 Javascript
使用focus方法让光标默认停留在INPUT框
Jul 29 Javascript
JavaScript生成福利彩票双色球号码
May 15 Javascript
详解JavaScript ES6中的模板字符串
Jul 28 Javascript
巧用jQuery选择器提高写表单效率的方法
Aug 19 Javascript
js实现符合国情的日期插件详解
Jan 19 Javascript
angularjs利用directive实现移动端自定义软键盘的示例
Sep 20 Javascript
jquery ajax异步提交表单数据的方法
Oct 27 jQuery
详解vue-cli之webpack3构建全面提速优化
Dec 25 Javascript
Angular6 写一个简单的Select组件示例
Aug 20 Javascript
详解使用element-ui table组件的筛选功能的一个小坑
Nov 02 Javascript
Vue 动态添加路由及生成菜单的方法示例
Jun 20 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图像处理类代码分享
2012/01/19 PHP
php使用mb_check_encoding检查字符串在指定的编码里是否有效
2013/11/07 PHP
php+mysql删除指定编号员工信息的方法
2015/01/14 PHP
CodeIgniter配置之autoload.php自动加载用法分析
2016/01/20 PHP
PHP实现移除数组中为空或为某值元素的方法
2017/01/07 PHP
PHP-FPM的配置与优化讲解
2019/03/15 PHP
javascript parseInt与Number函数的区别
2010/01/21 Javascript
js RuntimeObject() 获取ie里面自定义函数或者属性的集合
2010/11/23 Javascript
jquery带有索引按钮且自动轮播切换特效代码分享
2015/09/15 Javascript
浅谈toLowerCase和toLocaleLowerCase的区别
2016/08/15 Javascript
微信小程序(应用号)开发新闻客户端实例
2016/10/24 Javascript
Nodejs+angularjs结合multiparty实现多图片上传的示例代码
2017/09/29 NodeJs
浅谈vue引入css,less遇到的坑和解决方法
2018/01/20 Javascript
vue.js element-ui tree树形控件改iview的方法
2018/03/29 Javascript
手动用webpack搭建第一个ReactApp的示例
2018/04/11 Javascript
vue 不使用select实现下拉框功能(推荐)
2018/05/17 Javascript
解决vue中虚拟dom,无法实时更新的问题
2018/09/15 Javascript
JS实现随机抽选获奖者
2019/11/07 Javascript
微信小程序实现时间进度条功能
2020/11/17 Javascript
javascript操作向表格中动态加载数据
2020/08/27 Javascript
uniapp实现可以左右滑动导航栏
2020/10/21 Javascript
[06:07]辉夜杯现场观众互动 “比谁远送显示器”
2015/12/26 DOTA
python在windows下实现ping操作并接收返回信息的方法
2015/03/20 Python
Python环境下安装使用异步任务队列包Celery的基础教程
2016/05/07 Python
详解Python 模拟实现生产者消费者模式的实例
2017/08/10 Python
基于Python os模块常用命令介绍
2017/11/03 Python
10 行 Python 代码教你自动发送短信(不想回复工作邮件妙招)
2018/10/11 Python
Python遍历文件夹 处理json文件的方法
2019/01/22 Python
python解释器pycharm安装及环境变量配置教程图文详解
2020/02/26 Python
CSS3实现时间轴效果
2016/07/11 HTML / CSS
后勤采购员岗位职责
2013/12/19 职场文书
外企财务年会演讲稿
2014/01/03 职场文书
会计职业生涯规划书
2014/01/13 职场文书
餐厅采购员岗位职责
2014/03/06 职场文书
小兵张嘎观后感
2015/06/03 职场文书
酒店厨房管理制度
2015/08/06 职场文书