首页 > 代码库 > 各种数据类型在jvm里的内存分配
各种数据类型在jvm里的内存分配
jvm运行时数据区的简单介绍
JVM所管理的内存分为以下几个运行时数据区:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区。
其中本文涉及到的主要有:java虚拟机站(简称java栈),java堆和方法区。
这里简单地普及一下这三种数据区的知识,java栈的读取速度是最快的(紧次与CPU的寄存器,跨平台性比寄存器好,android使用的是寄存器),但是里面的数据内存大小是编译时就已经分配好的,在运行时都不会改变;java堆的速度没有java栈的速度那么快,但是java堆里面的数据内存大小不是固定的;前面两种都会被java的垃圾收集器清除废弃的内存;方法区对于Sun HotSpot来说,又称为“永久代”,虚拟机规范允许该区域可以选择不实现垃圾回收,相对而言,垃圾收集行为在这个区域比较少出现,该区域的内存回收目标主要针是对废弃常量的和无用类的回收。
基本数据类型
在java中,基本数据类型有:字节型(byte),短整型(short),整型(int),长整型(long),字符型(char),浮点型(float),双精度型(double),布尔型(boolean)。
基本数据类型都有一个共同点,就是它们的字节大小已经本身就已经固定的,所以,它们所需要的内存空间也是固定的。
根据上面jvm的简单介绍,基本数据类型实际上是放到java栈中的,这样可以保证基本数据类型的读取速度是最快的,而且基本数据类型用得也比较多。
对象实例及其引用
对于对象实例,总所周知,它的内存大小是不确定的,而且它也经常需要被垃圾收集器回收内存,所以它实际上是放在jvm里的java堆中;
对于引用类型(即对象引用),它的大小是固定的,而且在运行时需要快速找到引用,它实际上是放在jvm的java栈中。
对于Object obj = new Object(); 在java堆中有两种实现方法,一种是在java堆中多实现了一个句柄池,句柄池中放入到对象实例数据的指针,即java栈中的引用指向java堆中句柄池中的对象实例数据指针,再拿到实例数据;另一种是java堆中没用句柄池,java栈中的引用直接指向java堆中的实例数据。两种实现对比:第一种实现多了一个中间过程,当对象实例数据地址移动了,java栈中的引用不用变,只变句柄池的指针就行了;第二种实现,少了一个指针指向过程,速度比第一种快,但对象实例数据地址移动了,java栈中的引用也要改变。
借用一篇博文的图片:第一种
第二种:
字符串类型
String是一个特殊的对象,它的内存存放不用于普通对象类型。
首先,它是一个常量,一旦确定好就不会再改变,如:String str = "erdangjiade" + " " + "blog"; 这句代码会将"erdangjiade"、" "和"blog"分别放入jvm里面,再将"erdangjiade blog"放入jvm里面。所以为什么用StringBuffer的原因是StringBuffer是可变的。
讲了那么多,那么到底String是放去jvm哪里呢,如果从百度上找,会找到很多误导人的答案,字符串实际上是放在字符串常量池里面,字符串常量池是在常量池里面,而常量池是在方法区里面。所以字符串实际上是放在方法区里面的。
但是字符串引用还是存放在java栈中,直接指向方法区的常量池。
如果是new String(""); 这种方法得到的字符串不是放入字符串常量池中,而是当成一个普通对象放在java堆中的,例子:
String str = "erdangjiade";
String newStr = new String("erdangjiade");
当判断str==newStr时,会返回false,因为它们的地址不一样。(普及一个知识:==是比较两个对象的地址,equal()是比较对象数据是否相等)
方法区还存放被虚拟机加载的类信息,如:类类型,父类型,接口,方法及其方法参数等,反射中经常用到。所以方法区存放的数据特点是:静态的,基本的,共享的。
欢迎大家补充说明
参考文章:
兰亭风雨的【深入Java虚拟机】之一:Java内存区域与内存溢出
ZangXT的小例子:如何说明String常量池的位置
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。