你需要简单了解JVM中的内存长什么样子
下面有关JVM内存,说法错误的是?
1、程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程隔离的
2、Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的
3、方法区用于存储JVM加载的类信息、常量、静态变量、即使编译器编译后的代码等数据,是线程隔离的
4、原则上讲,所有的对象都在堆区上分配内存,是线程之间共享的
首先要回答这个问题,那么就要清楚jvm中内存是长什么样子的。
我遇到这个问题的时候,也只是简单的了解,因为没有做过什么对于java性能的优化,所以对于JVM不是很了解,所以还是要熟悉一下。
首先看一张图
这张图简单表示了jvm的内存是长什么样子的。
首先是颜色上面,蓝绿色的是非线程共享的,而黄色的是线程共享的。
然后是大小,大的我们用的多,而且需要掌握,小的我们只需了解,用的不是特别多。
我们先解释简单的
程序计数器。
其实这个东西很好理解,这个东西就相当于一个箭头,就和你断点调试的箭头一样,程序走到哪一步,他就到了那里。
他的功能就是用来告诉虚拟机现在走到了第几行代码了。然后你仔细想一下,这个箭头肯定是不能线程共享的,为什么呢?
每一个类都有每一个类的方法,多个用户肯定有可能会调用多个方法,每个方法有每个方法执行的的顺序,时间,所以一个人来了肯定会重新分配一个,大家不可能都用一个。
本地方法栈。
这货也好理解,你就把他当做栈,它里面呢,就是运行一些系统本地方法是需要用的。本地方法栈为使用到的本地操作系统(Native)方法服务。
还有三个就是重点了。
要理解,就要new对象了。
让我们来从new对象的执行顺序来理解这三个东西。
首先一个类在被jvm的类加载器加载的时候,它会把这个类的信息、常量、静态变量、编译器编译后的代码等数据存放到方法区里面去。还有静态变量也会存进去。常量存到常量池里面去。也就是说。方法区就像一个图书馆,把那些加载好的东西都存起来,等着备用。
然后一个类被new的时候,首先会在方法区中找这个类,找到一模一样的,然后在堆里面新建一个,然后先对一些变量初始化。基本变量赋值,对象赋值null。该对象的方法,会指向方法区中这个对象方法的地址。也就是说,多个相同的对象在堆中是保存了方法的地址,而没有把方法再复制一遍。
最后是一个对象被赋值的时候,注意刚才只是new A();而不是A a = new A();现在才是。当这一步的时候,会在java栈中建一个名字叫a的东西,然后把它的地址写成A在堆中的地址。
其实呢,栈里面还有很细的东西,它的内部结构是
但是我们可能不需要了解那么深入,有兴趣的同学自己去看呗。这里简单理解就好。
然后来理解选项
1、程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程隔离的
2、Java方法执行内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的
3、方法区用于存储JVM加载的类信息、常量、静态变量、即使编译器编译后的代码等数据,是线程隔离的
4、原则上讲,所有的对象都在堆区上分配内存,是线程之间共享的
1、前面已经说过了,这边不多说。
2、中Java方法执行内存模型,其实就是java栈,看上面的内部结构,前半部分就是对的。那么后半部分呢?
每一个用户过来,都是一个线程,每一个线程都需要有方法执行的顺序,那么都需要一个栈。所以不是线程共享的。
3、方法区加载的那些信息肯定是对的,但是对于方法区来说,并不是每个线程过来都用用一个新的方法区,因为之前说过它就是一个图书馆,堆只要往里面拿就好了,而且编译加载之后方法区里面已经有东西了,而且那些方法,常量都是可以复用的,所以方法区肯定是共享的.
4、对象都是在堆中new出来的,为什么是线程共享的呢,线程共享的区域与JAVA程序运行的生命周期相同。这部分空间是Java垃圾收集器管理的主要区域。这些对象都是由GC管理回收的。所以是线程共享的。
下面是参考资料:如果想仔细了解的同学看下面的,别看我的。
http://www.cnblogs.com/dolphin0520/p/3613043.html