From b6394ef58755eb340266c7c9aeaf364c475c97c0 Mon Sep 17 00:00:00 2001 From: Coder Date: Tue, 19 May 2020 20:42:01 +0800 Subject: [PATCH 1/3] =?UTF-8?q?Update=2002=E7=AB=A0-Java=E9=87=8C=E7=9A=84?= =?UTF-8?q?=E5=90=84=E7=A7=8D=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B=E5=8D=A0?= =?UTF-8?q?=E7=94=A8=E5=A4=9A=E5=B0=91=E5=86=85=E5=AD=98=E7=A9=BA=E9=97=B4?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...05\345\255\230\347\251\272\351\227\264.md" | 37 +++---------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git "a/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" "b/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" index 8f0c368..ea37f83 100644 --- "a/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" +++ "b/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" @@ -19,7 +19,6 @@ 请问老师,Merchandise m1这个引用类型变量是多大呢?或者说为了存储实例的地址,需要给m1多大的内存? ``` -我思来想去,这事儿没有一篇文章还真扯不清楚。有兴趣的同学请继续阅读 # Java 程序员需要关心数据类型对内存的占用情况吗? @@ -29,47 +28,21 @@ Java 用跑在虚拟机里,并且有一个严格得虚拟机规范,就是让 但是不必了解,并非是了解了没用。不了解也能写出好代码,了解了之后在某些情况下可以写出更好的代码。尤其是在对程序关键点的数据结构设计和预估程序总体内存占用情况时,会有帮助。 -# 每种数据类型占用的内存是固定的吗? - -不是。不是。不是。重要的事情说三遍。 - -不固定有几个维度,下面分别说说在不同的情况下占用的内存为什么不固定,以及在不同情况下具体占用多少内存。 - ## JVM 规范没规定 -JVM 规范从来没有规定每种数据类型占用多大的内存。它只是给出了每种数据类型的值域。严谨的不要不要的。既然规范没有说,那么肯定占用的内存就是不固定的喽。具体占用多少,得看规范得实现。 +JVM 规范从来没有规定每种数据类型占用多大的内存。它只是给出了每种数据类型的值域。严谨的不要不要的。既然规范没有说,那么肯定占用的内存就可以是不固定的喽。具体占用多少,得看规范得实现。 那么具体到某种实现,就是固定得了么? -## JDK 实现:看位数和内存区域 - -前面我们讲解基本数据类型的时候,不严谨的说了每种数据类型占用的内存。那个数字也是主流的 JDK 占用的内存。但是那个数字忽略了 JDK 的位数和数据所在的内存区域。 - -### JDK 的位数 +## JDK 实现:看位数 很多年前,主流的操作系统和 CPU 都是32位的。什么意思呢,就是 CPU 的指令能够处理的数,都是32位的,包括内存寻址,也是32位的。所以32位的系统下,可以使用的内存不能超过4G,因为32位的寻址空间只能表示这么大的内存地址范围。 -后来出现了64位的操作系统和 CPU,寻址空间和 CPU 操作数都是64位了。CPU的操作数都是64位了,那么应用程序喂给 CPU 的数据也得是64位的呀。 - -Java 进程也是操作系统上的应用程序。我们知道程序都分64位版和32位版。JDK 也一样。不同的版本在不同情况下占用的内存也不一定一样。 - -主流 JDK 的内存按照用途主要被分成方法区,堆,和方法栈(其实还有本地方法栈和 PC 寄存器,但是存在感和前三个比太低了,这里不说了)。在不同的区域,占用内存也不大一样,下面大概说说。 - -### JDK 内存区域:方法区 - -什么是方法区内存呢?直观来说就是保存我们写的方法里的代码的内存。也就是包括我们写的方法里的各种表达式指令,局部变量(当然也包括引用),字面值(literal value),参数这些数据。对于一个类来说,无论它的对象有多少个,方法区占用的内存是不变的,因为他们的代码是一样的嘛。 - -那么各种数据类型在方法区里占用的内存是多大呢?就是我们之前说的那个大小。比如int是4个字节,long是8个字节。无论是32位还是64位。 - -### JDK 内存区域:方法栈 - -方法栈是执行方法区里代码的时候需要的内存,也就是我们debug的时候看到的那个一层压着一层的frame。 - -作为 Java 进程中给 CPU 喂数据的栈(方法栈),就是以64位为一个单位安排的。也就是说,通常情况下,在方法栈上,无论是什么数据类型,都最少占用64个bit,也就是8个byte。说的更具体一点,方法里写的局部变量,字面值(literal value),参数,都是至少占用8个字节。当然好像也没有需要占用更多字节的数据类型,毕竟double和long都是8个字节就够表示规范中的值域了。 +后来出现了64位的操作系统和 CPU,寻址空间和 CPU 操作数都是64位了。Java 进程也是操作系统上的应用程序。我们知道程序都分64位版和32位版,JDK 也一样。 -### JDK 内存区域:内存堆 +对于栈和堆的上的数据,可以分配的有基本数据类型和引用类型。 -Java 的对象是分配在堆上的。就是我在课程中说的那个公告板。堆上的数据在被 JVM 指令使用的时候,会被弄到栈上去。但是保存在堆上的时候,和方法区一样,就是按照之前说的普通情况占用该占用的内存。 +基本数据类型很简单,大部分JVM都会按照值域来分配最小的需要的内存,这个我们在前面已经介绍过。 ## 引用类型:磨人的小妖精 From 15484ab30b8f342936bced01e14ce2e04deca0f3 Mon Sep 17 00:00:00 2001 From: Coder Date: Tue, 19 May 2020 20:42:48 +0800 Subject: [PATCH 2/3] =?UTF-8?q?Update=2002=E7=AB=A0-Java=E9=87=8C=E7=9A=84?= =?UTF-8?q?=E5=90=84=E7=A7=8D=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B=E5=8D=A0?= =?UTF-8?q?=E7=94=A8=E5=A4=9A=E5=B0=91=E5=86=85=E5=AD=98=E7=A9=BA=E9=97=B4?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...345\206\205\345\255\230\347\251\272\351\227\264.md" | 10 ---------- 1 file changed, 10 deletions(-) diff --git "a/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" "b/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" index ea37f83..03b33cd 100644 --- "a/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" +++ "b/FAQ/02\347\253\240-Java\351\207\214\347\232\204\345\220\204\347\247\215\346\225\260\346\215\256\347\261\273\345\236\213\345\215\240\347\224\250\345\244\232\345\260\221\345\206\205\345\255\230\347\251\272\351\227\264.md" @@ -1,15 +1,5 @@ -- [来自@谭低调 同学的问题:引用占用多少内存?](#%e6%9d%a5%e8%87%aa%e8%b0%ad%e4%bd%8e%e8%b0%83-%e5%90%8c%e5%ad%a6%e7%9a%84%e9%97%ae%e9%a2%98%e5%bc%95%e7%94%a8%e5%8d%a0%e7%94%a8%e5%a4%9a%e5%b0%91%e5%86%85%e5%ad%98) -- [Java 程序员需要关心数据类型对内存的占用情况吗?](#java-%e7%a8%8b%e5%ba%8f%e5%91%98%e9%9c%80%e8%a6%81%e5%85%b3%e5%bf%83%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e5%af%b9%e5%86%85%e5%ad%98%e7%9a%84%e5%8d%a0%e7%94%a8%e6%83%85%e5%86%b5%e5%90%97) -- [每种数据类型占用的内存是固定的吗?](#%e6%af%8f%e7%a7%8d%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e5%8d%a0%e7%94%a8%e7%9a%84%e5%86%85%e5%ad%98%e6%98%af%e5%9b%ba%e5%ae%9a%e7%9a%84%e5%90%97) - - [JVM 规范没规定](#jvm-%e8%a7%84%e8%8c%83%e6%b2%a1%e8%a7%84%e5%ae%9a) - - [JDK 实现:看位数和内存区域](#jdk-%e5%ae%9e%e7%8e%b0%e7%9c%8b%e4%bd%8d%e6%95%b0%e5%92%8c%e5%86%85%e5%ad%98%e5%8c%ba%e5%9f%9f) - - [JDK 的位数](#jdk-%e7%9a%84%e4%bd%8d%e6%95%b0) - - [JDK 内存区域:方法区](#jdk-%e5%86%85%e5%ad%98%e5%8c%ba%e5%9f%9f%e6%96%b9%e6%b3%95%e5%8c%ba) - - [JDK 内存区域:方法栈](#jdk-%e5%86%85%e5%ad%98%e5%8c%ba%e5%9f%9f%e6%96%b9%e6%b3%95%e6%a0%88) - - [JDK 内存区域:内存堆](#jdk-%e5%86%85%e5%ad%98%e5%8c%ba%e5%9f%9f%e5%86%85%e5%ad%98%e5%a0%86) - - [引用类型:磨人的小妖精](#%e5%bc%95%e7%94%a8%e7%b1%bb%e5%9e%8b%e7%a3%a8%e4%ba%ba%e7%9a%84%e5%b0%8f%e5%a6%96%e7%b2%be) # 来自@谭低调 同学的问题:引用占用多少内存? From 6010081c60df28300110975ac0eb2b825ca76a05 Mon Sep 17 00:00:00 2001 From: Coder Date: Sat, 23 May 2020 14:41:04 +0800 Subject: [PATCH 3/3] =?UTF-8?q?Update=2002=E7=AB=A0-=E4=B8=BA=E4=BB=80?= =?UTF-8?q?=E4=B9=88=E6=9E=84=E9=80=A0=E6=96=B9=E6=B3=95=E4=B8=AD=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E9=87=8D=E8=BD=BD=E7=9A=84=E6=9E=84=E9=80=A0=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=BF=85=E9=A1=BB=E5=BE=97=E6=98=AF=E5=9C=A8=E7=AC=AC?= =?UTF-8?q?=E4=B8=80=E8=A1=8C.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\257\345\234\250\347\254\254\344\270\200\350\241\214.md" | 6 ++++++ 1 file changed, 6 insertions(+) diff --git "a/FAQ/02\347\253\240-\344\270\272\344\273\200\344\271\210\346\236\204\351\200\240\346\226\271\346\263\225\344\270\255\350\260\203\347\224\250\351\207\215\350\275\275\347\232\204\346\236\204\351\200\240\346\226\271\346\263\225\345\277\205\351\241\273\345\276\227\346\230\257\345\234\250\347\254\254\344\270\200\350\241\214.md" "b/FAQ/02\347\253\240-\344\270\272\344\273\200\344\271\210\346\236\204\351\200\240\346\226\271\346\263\225\344\270\255\350\260\203\347\224\250\351\207\215\350\275\275\347\232\204\346\236\204\351\200\240\346\226\271\346\263\225\345\277\205\351\241\273\345\276\227\346\230\257\345\234\250\347\254\254\344\270\200\350\241\214.md" index 0e24cc0..113e074 100644 --- "a/FAQ/02\347\253\240-\344\270\272\344\273\200\344\271\210\346\236\204\351\200\240\346\226\271\346\263\225\344\270\255\350\260\203\347\224\250\351\207\215\350\275\275\347\232\204\346\236\204\351\200\240\346\226\271\346\263\225\345\277\205\351\241\273\345\276\227\346\230\257\345\234\250\347\254\254\344\270\200\350\241\214.md" +++ "b/FAQ/02\347\253\240-\344\270\272\344\273\200\344\271\210\346\236\204\351\200\240\346\226\271\346\263\225\344\270\255\350\260\203\347\224\250\351\207\215\350\275\275\347\232\204\346\236\204\351\200\240\346\226\271\346\263\225\345\277\205\351\241\273\345\276\227\346\230\257\345\234\250\347\254\254\344\270\200\350\241\214.md" @@ -22,6 +22,12 @@ DNT回复:我好像在视频里提过一嘴, 但是是在后面讲解super的 首先说一下为什么"子类的构造方法, 会强制在第一行调用父类的构造方法", 这个我在视频里提了一嘴, **(人工划重点)这是因为子类可以访问父类的方法和属性. 那么必须保证子类的对象在做任何事情之前, 子类里那个隐含的父类对象, 必须初始化完成. 否则, 初始化都没完成, 调用方法, 返回属性, 都可能得到的是不对的状态/值(人工划重点结束)**. +那么这里说的初始化是什么呢?就是给对象里的属性设置正常的值,或者执行一些方法。简单来说,创建一个对象拢共分两步,一步是在堆上分配内存,然后在这个内存里存储对象的属性。下一步就是初始化对象,也就是执行构造方法。只有执行完毕构造方法,这个对象才算是可以被使用了。 + +这里可能有的一个疑问是,对象都创建出来了,初始化不初始化的不都能用么?其实不是那么回事儿。对象初始化可以做的事情很多,比较普遍的是初始化属性的值,也可能会调用一些方法,完成一些业务逻辑要求的初始化代码。从业务逻辑上来说,对象没有初始化完,是不应该被使用的。 + +举个例子,在堆上分配内存,就是买了一堆电脑硬件,什么内存,CPU,硬盘主板。初始化就是把这些零件拼装起来,组成一个电脑,并且给它装上操作系统。在完成初始化之前,电脑不是能被使用的电脑,只是一堆零件。同样的道理,在完成初始化之前,对象也不是对象,只是一堆内存。 + 好, 知道了这一点之后, 很自然的可以推出, this调用必须也在第一行, 否则的话, this调用里会调用父类构造方法, 如果this不是第一句, 那么也就隐含着调用父类构造方法不是第一句, 也就是说, 子类可能使用的父类的属性或者方法是没有初始化完成的. 其实我也觉得这个挺别扭, 拿参数稍微算一下,再给构造方法不行吗? 但是这个确实很难控制, 或者说没必要做这么复杂. 是给自己挖坑. 所以干脆一刀切, super必须是第语句, this也必须是第一句.