zoukankan      html  css  js  c++  java
  • JVM 学习笔记(四)

    回顾:

      在之前的文章中,我们主要体现了当堆内存设置的比较小的情况下,比如:-Xmx20M -Xms20M,在项目运行的过程中,不断往内存中去添加对象,

    这时候就会出现OOM,也就是内存溢出,本文章将展示方法区和虚拟机栈内存溢出的情况。

    方法区内存溢出:

      为了使方法区内存溢出,我们将JVM的参数调整为:-XX:MetaspaceSize=50M -XX:MaxMetaspaceSize=50M。然后不断的往方法区中添加class信息,

    前面我们介绍了方法区的作用是:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

    代码如下:

    //pom.xml中添加如下依赖
    <dependency> 
        <groupId>asm</groupId> 
        <artifactId>asm</artifactId> 
        <version>3.3.1</version> 
    </dependency>
    
    
    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();
                Metaspace test = new Metaspace();
                byte[] code = cw.toByteArray();
                Class<?> exampleClass = test.defineClass("Class" + i, code, 0, code.length);
                classes.add(exampleClass);
            }
            return classes;
        }
    }

      执行代码,果然会包方法区内存溢出:

     虚拟机栈内存溢出:

      前面我们介绍虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。换句话说,一个Java线程的运行状态,由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的,独有的,随着线程的创建而创建。每一个被线程执行的方法,为该栈中的栈帧,即每个方法对应一个栈帧。调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出。

      代码演示:

    public class StackDemo {
        public static long count = 0;
    
        public static void method(long i) {
            System.out.println(count++);
            method(i);
        }
    
        public static void main(String[] args) {
            method(1);
        }
    }

      结果:

      理解和说明:

      Stack Space用来做方法的递归调用时压入Stack Frame(栈帧)。所以当递归调用太深的时候,就有可能耗尽Stack Space,爆出StackOverflow的错误。-Xss128k:设置每个线程的堆栈大小。JDK 5以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
      线程栈的大小是个双刃剑,如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大,如果该值设置过大,就有影响到创建栈的数量,如果是多线程的应用,就会出现内存溢出的错误。
  • 相关阅读:
    简单组网(根据MAC地址划分VLAN)
    简单组网(根据接口划分VLAN)
    简单组网(LACP)负载分担链路聚合
    简单组网(Eth-Trunk)负载分担链路聚合
    《数字图像处理_第三版_中_冈萨雷斯》第一章笔记
    安全测试类型
    全链路压测
    容量测试与容量规划
    性能测试详细介绍
    树莓派vnc连接,放歌调节声音
  • 原文地址:https://www.cnblogs.com/talkingcat/p/13283464.html
Copyright © 2011-2022 走看看