Chapter 2 - Everything is an Object

Java内存的故事


Stack堆栈, 和Heap堆
先科普一下计算机里内存内存的结构:

每当一个程序被执行,系统就要为它开启一个进程,并且为它分配内存。从低址区到高址区,分成几个不同的区域。
低址:存放程序代码本身。
次低址:存放全局变量,无论是初始化的还是未初始化的。
中址:就是堆和堆栈的区域。用来储存进程运行过程中产生的变量。
最高址:为系统额外预留的空间。我们无法操作。

stack(堆栈)
从高址区往下延展。用来存储Scoped Variable(限域变量)。简单说就是已知存储空间以及生命周期的变量。为什么stack效率高呢?因为变量大小确定,都是紧挨着储存的,在堆栈中创建和释放储存空间只要一条汇编语言,分别是将栈顶指针向下和向上移动。而stack本身又是LIFO(Last in First out)的,所以效率极高。

heap(堆)
从较低地址区往上移动。heap是个动态内存池。从下面的图我们看的很清楚,heap不像stack那样是数据是连续的。heap的数据是不连续的,动态随便乱贴的。创建和释放效率都不高。

Java对象存在哪儿?
“引用”存放在”stack”(堆栈)中

Java声称一切都是对象,Java完全采用了动态内存分配方式。这是因为所有创建的对象全都继承自单根基类Object,而这个Object又只能以唯一的方式从heap堆中创建。

对于 Java 应用程序,实际上包含两个池:Java 堆和本机(非 Java)堆。Java 堆的大小由 JVM 的 Java 堆设置控制:-Xms 和 -Xmx 分别设置最小和最大 Java 堆。在按照最大的大小设置分配了 Java 堆之后,剩下的用户空间就是本机堆

本机堆里包含JVM堆。剩下的就是空闲Native堆。上图中显得Java数据好像全在heap里,完全不用stack。这是不准确的,Java用stack!实际上,Java每个对象都有一个指向他的指针,叫”引用“。可以理解为C++的指针。Java不是不用指针,只是泛化他,看下面这个声明
String s;
这里s创建的只是”引用”,并不是”对象”。这时候还没有对象,只有引用。这时候如果要求输出s,系统会返回错误。
对象的引用存放在”stack“(堆栈)中。
“对象”存放在”heap”(堆)中|

new关键字,负责创建对象。对象存放在heap(堆)中。看下面的例子,
String s = new String("hello");
这时候s是reference引用,存在stack堆栈里。String(hello)是对象,存在heap堆中。

当然,我们可以用另一种”奇怪”的方式声明一个String,
String s = "hello";
这里不用new关键字,只不过是Java的一个”特性”,并不是本性。只是说Java用了特殊的方法,形式上允许不用new来创建一个String对象,可以直接赋值。但本质上,Java内部处理以后,这个”hello”还是以对象的方式存在heap区里。

例外
特别强调八种基本类型
因为他们不属于对象,不存放在heap堆区,而是直接存在stack堆栈区。因为他们的所占用的存储空间和生命周期都是已知的。
让我们再瞻仰一下他们伟岸的面容。其实下面有九种,因为加上了一个void空型。

int: 4字节 (32比特,1字节=8比特)

基本类型对应的包装器类是在堆中创建的非基本对象。

一个Java对象里有些啥?
Java一切都是对象的理念很美,但付出的内存的代价也是巨大的。对象的元数据,大小相当惊人,一般都是他们存放的数据本身的好几倍,根据 JVM 的版本和供应的不同,对象元数据的数量也各有不同,但其中通常包括:

类:一个指向类信息的指针,描述了对象类型。举例来说,对于 java.lang.Integer 对象,这是 java.lang.Integer 类的一个指针。
标记:一组标记,描述了对象的状态,包括对象的散列码(如果有),以及对象的形状(也就是说,对象是否是数组)。
锁:对象的同步信息,也就是说,对象目前是否正在同步。

对象元数据后紧跟着对象数据本身,包括对象实例中存储的字段。对于 java.lang.Integer 对象,这就是一个 int。 如果您正在运行一个 32 位 JVM,那么在创建 java.lang.Integer 对象实例时,对象的布局可能如下图所示。也就是说,为了储存一个32位的int数据,java要占用128位内存。

上图更正提示:数组元数据占用了其余128位,存单值的数组总共160位,而包装器Integer占用128位,因此数组成本更高

Java的作用域
前面说过了,java把对象的引用存在stack区,把对象存在heap区。看下面这张图

所有存在stack区的内容,还是遵守花括号{}的作用域,比如基本型i=4,y=2,还有对象的引用cls1,出了域的终点–花括号,就都消失了,所以他们的作用域和占用空间是已知的。但在heap区的对象本身还存在,并没有被销毁。只是我们已经找不到他了,因为指向他的引用cls1已经擦除了。

这是Java很好的一个特性,因为只要我们注意传递和复制对象的引用,在后面的程序中我们一直可以调用这个对象。因为只要有一个引用能让我们找到他,他一直在那儿。

另一个好处(对程序员),但也可以说是坏处(对系统),就是一旦一个对象完全失去引用,我们不必像C++这样手动用delete()释放heap区的对象。我们可以完全不去管它。但我们不管他,意味着必须有别人去管它,这就是JVM里的垃圾回收器(Garbage Collection)。但因为处理的对象都是heap区里的家伙,所以开销要大很多,对系统负担也很大。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容