Learning together JVM- memory structures - area method (Method Area) (thread shared area)

Method region (Method Area)

Definition: storing information associated with a category, such as: fields, methods, constructors and constant pools.
It is logically part of the heap, but implementation is different. For example: oracle's Hotspot JVM
implementations area called permanent generations prior to 1.8, is the use of the heap as part of the method area.
But after 1.8 implementation zone is called Yuan space, using a local memory is the system memory.
Here Insert Picture Description
Features:
1. All Java threads share a region
2 can occur outOfMemoryErrot (memory overflow)
method of generating scene area out of memory:
a dynamic scene is generated and loaded class: such as,
Spring cglib generated using the proxy class, mybatis dynamically generating cglib etc. mapper interface implemented
before JDK1.8, spring, mybatis dynamically generated class or the like easily cause permanent generation memory overflow.
After 1.8, because the yuan is system memory space used, a lot of relatively abundant, but garbage collection is managed by its own
demo code:
1.8 the previous generation of memory overflow can cause permanent:
Note: This code is used in JDK1.6 version

/**
 * 演示永久代内存溢出  java.lang.OutOfMemoryError: PermGen space
 * 设置启动参数,永久代最大内存为8M: -XX:MaxPermSize=8m
 */
public class Demo1_6 extends ClassLoader {// 可以用来加载类的二进制字节码
    public static void main(String[] args) {
        int j = 0;
        try {
            Demo1_6 test = new Demo1_6();
            for (int i = 0; i < 20000; i++, j++) {
                // ClassWriter 作用是生成类的二进制字节码
                ClassWriter cw = new ClassWriter(0);
                // 参数:版本号, public, 类名, 包名, 父类, 接口
                cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);
                // 返回 byte[]
                byte[] code = cw.toByteArray();
                // 执行了类的加载
                test.defineClass("Class" + i, code, 0, code.length);// Class 对象
            }
        } finally {
            System.out.println(j);
        }
    }
}

After 1.8 yuan will lead to memory overflow space:
After the code is used in JDK1.8 version, and Note:

/**
 * 演示元空间内存溢出 java.lang.OutOfMemoryError: Metaspace
 * 设置启动参数,元空间最大内存为8M: -XX:MaxMetaspaceSize=8m
 */
public class Demo1_8 extends ClassLoader { // 可以用来加载类的二进制字节码
    public static void main(String[] args) {
        int j = 0;
        try {
            Demo1_8 test = new Demo1_8();
            for (int i = 0; i < 10000; i++, j++) {
                // ClassWriter 作用是生成类的二进制字节码
                ClassWriter cw = new ClassWriter(0);
                // 版本号, public, 类名, 包名, 父类, 接口
                cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);
                // 返回 byte[]
                byte[] code = cw.toByteArray();
                // 执行了类的加载
                test.defineClass("Class" + i, code, 0, code.length); // Class 对象
            }
        } finally {
            System.out.println(j);
        }
    }
}

Runtime constant pool

定义:
常量池:就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量
等信息
运行时常量池:常量池是 class 文件中的,当该类被加载进虚拟机,它的常量池信息就会放入运行时常量
池,并把里面的符号地址变为真实的内存地址
演示代码:

// 二进制字节码(类基本信息,常量池,类方法定义,包含了虚拟机指令)
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}

输入指令: javac HelloWorld.java-将HelloWorld 类编译成class文件
输入指令:javap -v HelloWorld.class-将class二进制文件反编译

StringTable(串池)

首先看一段面试代码:

 public class Demo1 {
    public static void main(String[] args) {
        String s1 = "a"; 
        String s2 = "b";
        String s3 = "ab";
        String s4 = s1 + s2;
        String s5 = "a" + "b";  
        //问
        System.out.println(s3 == s4);
        System.out.println(s3 == s5);
    }
}

请问,在不运行的情况下,能否明确肯定的说出结果,如果不能,请看以下分析。
常量池与串池(StringTable)的关系:
1.类加载时常量池中的信息,都会被加载到运行时常量池中, 这时 a,b,ab 都是常量池中的符号,还没有变为 java 字符串对象。
2.第一次用到时才变为对象(懒惰的方式:延迟加载)
3.变成String对象后就会把它当成key到StringTable中去找有没有取值相同的key。
4.StringTable的数据结构就是一个哈希表,长度一开始是固定可并且是不能扩容的。
5.第一次从StringTable中找取值相同的key肯定是没有的,他就会把这个值存入StringTable中。
字符串变量的拼接:

String s4 = s1 + s2;

字符串变量的拼接其实会有以下操作:
1.首先new StringBuilder();说到这你肯定就会想到之后的操作了
2.append一个s1对应的值,在append一个s2对应的值
3.调用toString方法
4.赋值给字符串变量s4
其实做String s4 = s1 + s2;这样的操作时,底层就是new StringBuilder().append("a").append("b").toString()
那么s3 == s4吗?

System.out.println(s3 == s4);输出结果是什么,相信心中有了答案

false
也许你有疑惑,s3的值是“ab”,s4的值是“ab”为什么是false呢?
问题就在StringBuilder的toString()这个方法里。
看toString的源码:

 @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

它是new了一个新的String对象。所以说System.out.println(s3 == s4)输出结果为false
字符串常量的拼接:

String s5 = "a" + "b";  

这个相对于变量的拼接就简单许多,它其实在编译期间就会优化,因为“a”是常量,“b”是常量,“a” + "b"肯定也是常量啊。结果已经在编译期确定为“ab”了。
那么 System.out.println(s3 == s5)输出的结果是什么呢?

true

你是否存在疑惑?其实很简单:

 String s3 = "ab";

This operation has the constant "ab" placed in the StringTable. After String s5 = "a" + "b";this operation will look for a value corresponding to the StringTable, because there StringTable "ab" value, so s3 and s5 pointing to the same constant "ab", the System.out.println(s3 == s5)result is output true.
StringTable features:
1. A string constant pool is only a symbol, when used for the first time become the object
mechanism 2. Use string pool to avoid duplication create a string object
3. The principle is the string variable splicing StringBuilder (1.8)
principle 4. stitching string constants are compiled optimization

Published 13 original articles · won praise 23 · views 6005

Guess you like

Origin blog.csdn.net/weixin_45240169/article/details/104042220