为什么 Java 堆可以处于物理上不连续的内存空间? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhao1014
V2EX    Java

为什么 Java 堆可以处于物理上不连续的内存空间?

  •  
  •   zhao1014 2020-11-07 11:47:11 +08:00 6090 次点击
    这是一个创建于 1848 天前的主题,其中的信息可能已经有所发展或是发生改变。

    JVM 为大对象分配内存时需要连续的内存空间,这个内存空间指的是逻辑上连续的内存空间吧?

    在物理内存中对象有可能被拆分开分配到物理不连续的空间中吗?

    如果 Java 堆逻辑连续的空间物理上并不连续,那么垃圾回收的过程中,由复制算法和标记-整理算法得到的空闲内存是不是也是逻辑上连续,物理上不一定连续?

    JVM 运行时数据区是不是对物理内存的一部分的封装?如果是封装,那么逻辑内存与物理内存之间是不是存在一映射关系?维护这个映射关系的开销不会很大么?为什么不要求物理连续呢?

    第 1 条附言    2020-11-07 12:39:19 +08:00
    感谢各位的回答!去研究操作系统了!
    38 条回复    2020-11-09 11:03:15 +08:00
    hello2060
        1
    hello2060  
       2020-11-07 11:51:23 +08:00 via iPhone
    没研究过这么高深的问题,既然 java 里都是指针,为啥必须连续空间?你一个对象创建出来只是把成员初始化了,这时候成员还不一定指向任何有意义的东西呢,连续空间有啥用
    vk42
        2
    vk42  
       2020-11-07 11:53:42 +08:00   3
    物理地址一般对用户态程序是不可见的,至于虚拟地址到物理地址映射是 OS 维护的事,JVM 没必要多管闲事
    zhao1014
        3
    zhao1014  
    OP
       2020-11-07 11:58:35 +08:00 via Android
    @hello2060 可是 jvm 分配大对象内存要求连续空间,指针指向的是对象所占内存空间的起始地址,也就是第一个字节的地址,再通过对象的类型得知该对象所需空间具体大小然后顺序读取内存
    noe132
        4
    noe132  
       2020-11-07 12:04:18 +08:00   1
    应用程序没有权限直接操作物理内存的,操作的都只是虚拟内存,内存分配是 OS 的工作。至于怎么分配,怎么映射,又多大开销,《操作系统》欢迎你
    zhao1014
        5
    zhao1014  
    OP
       2020-11-07 12:04:36 +08:00 via Android
    @vk42 好的,谢谢你
    zhao1014
        6
    zhao1014  
    OP
       2020-11-07 12:06:12 +08:00 via Android
    @hello2060 好像没能理解你说的意思,说的话跟你没对上,抱歉了
    zhao1014
        7
    zhao1014  
    OP
       2020-11-07 12:07:31 +08:00 via Android
    @noe132 你说的虚拟内存是不是虚拟存储器,本质上是存储在磁盘上,只在需要的时候才会被读取到内存里?
    djFFFFF
        8
    djFFFFF  
       2020-11-07 12:11:11 +08:00
    @zhao1014 虚拟内存是操作系统的知识,对物理内存的抽象和隔离。看一下操作系统的知识就知道了。
    zhao1014
        9
    zhao1014  
    OP
       2020-11-07 12:12:56 +08:00 via Android
    @djFFFFF 好的,谢谢!
    secondwtq
        10
    secondwtq  
       2020-11-07 12:20:39 +08:00 via iPhone   1
    “维护这个映射关系的开销不会很大么”
    这个开销由硬件承担。可能有其他的方案,但是现在主流硬件都针对这个优化,已经形成了路径依赖
    julyclyde
        11
    julyclyde  
       2020-11-07 12:22:41 +08:00   1
    应用程序看不到物理内存的地址空间
    所以讨论在物理地址空间是否连续根本就是个 NULL 问题
    BrettD
        12
    BrettD  
       2020-11-07 12:31:18 +08:00 via iPhone   1
    物理内存映射是操作系统内核管的事情,JVM 只管到逻辑地址
    hello2060
        13
    hello2060  
       2020-11-07 12:31:58 +08:00   1
    @zhao1014 虚拟内存应该只是一个虚拟的东西,他映射到实际存储数据的地方,可以在内存上也可以在磁盘里。

    我前面的回答其实和你问的不是一回事。但是比如说一个飞机对象,包含 100 个乘客对象,也就是飞机对象有 100 个乘客对象的 reference, 这些 reference 可以是在连续空间里的(不管实际存储位置是不是连续的),但是具体每一个乘客对象,完全可以在不连续的位置上(这个更不可能要求实际存储位置是连续的,因为每个乘客对象都是独立的,完全可以在不同的时间地点被创建)再到飞机对象被销毁的时候,乘客对象完全可能还继续存在着,要求物理连续没有意义啊。--- 如果我说的不是你问的,你可以忽略嘿嘿
    zhao1014
        14
    zhao1014  
    OP
       2020-11-07 12:37:24 +08:00 via Android
    @hello2060 哈哈,感谢回答
    temp178
        15
    temp178  
       2020-11-07 12:39:45 +08:00   1
    这里的连续地址,指的是虚拟内存的连续,而不是物理内存的连续。可以理解为虚拟内存统一受 JVM 管理,当分配大对象时候,需要在虚拟内存地址中,找到连续的内存(因为 JVM 管理虚拟内存,所以虚拟内存也是有碎片化使用的)
    misaka19000
        16
    misaka19000  
       2020-11-07 12:43:13 +08:00   2
    学学操作系统吧。。。CPU 有一个部件叫做 MMU,用来管理物理内存页。

    或者看我之前写的文章
    https://www.nosuchfield.com/2018/11/23/Program-compilation-linking-loading-and-running/
    中第四部“装载”中介绍的过程
    Jooooooooo
        17
    Jooooooooo  
       2020-11-07 12:53:51 +08:00   1
    你可以研究下操作系统虚拟内存和物理内存的映射管理.
    zhao1014
        18
    zhao1014  
    OP
       2020-11-07 13:03:08 +08:00 via Android
    @misaka19000 感谢,发现了一个错别字,
    “但其实每个旅行图手中的地图都是不一样的,这个地图保证客人绝对不会找到一个已经被别人使用的房间”旅行图→旅行团
    misaka19000
        19
    misaka19000  
       2020-11-07 13:42:05 +08:00
    @zhao1014 #18 感谢,已经修改
    nightwitch
        20
    nightwitch  
       2020-11-07 14:40:56 +08:00   1
    推荐去看 csapp 的第九章:虚拟内存,关键词:页表,换页和 page fault 。

    对应用程序来说内部见到的地址都是虚拟的,由虚拟地址往物理地址的映射这部分是由操作系统和硬件 mmu+tlb 单元来控制的。
    winglight2016
        21
    winglight2016  
       2020-11-07 17:57:52 +08:00   1
    JVM 里的对象不需要“连续内存空间”,lz 恐怕是以为所有和某个对象相关的数据都放在连续的内存地址中(假设不区分是物理地址还是 JVM 的虚拟地址),但是并不是这样,一个 java Object 只需要声明就好了(我记得只需要 52 个字节),具体的数据是存在堆栈内存中的。

    如果 lz 是专注 java 开发,那么是没必要了解 OS,先研究一下 JVM 吧。
    systemcall
        22
    systemcall  
       2020-11-07 19:02:14 +08:00   1
    应用程序能够访问到的都是“虚拟内存”
    硬盘上的是“页面文件”而不是“虚拟内存”,这 2 个不是一回事
    一般的应用程序是拿不到“物理内存”的地址的。虚拟内存是硬件实现的(现在是 CPU 里面的 MMU 之类的部分来做),一般的应用是看不到这些东西的
    Intel 这几年牙膏倒吸的漏洞,就和 Intel 的 MMU 的缺陷有关系,感兴趣的话可以看看
    另外,现在的 SSD 也是映射过的。NAND 闪存非常容易有坏块,而且还要做均衡磨损、垃圾回收等一系列的事情。操作系统里可以看到的 LBA 和 SSD 内部 NAND   Flash 上的位置不是一一对应的,而是由 SSD 主控负责映射。如果 SSD 有 DRAM 缓存的话,DRAM 用来存放映射表
    不用担心效率问题,因为是专门的硬件来完成。针对内存的一些性能测试,也在一定程度上反映了这套系统的性能
    irytu
        23
    irytu  
       2020-11-07 19:38:33 +08:00 via iPhone
    虚拟内存 物理地址都存在每个进程的页表 page table 里面 安全、好管理、也有利于简化一些内存相关的操作
    zhao1014
        24
    zhao1014  
    OP
       2020-11-07 20:10:56 +08:00 via Android
    @winglight2016 我是看了深入理解 java 虚拟机中垃圾回收方面的东西才有了这种想法,比如说:
    使用复制算法留下的空间是规整的,标记清除算法会产生大量碎片空间,此时 jvm 会维护一个空闲列表来记录空闲内存,在为对象分配内存时选取足够大的连续空间。

    所以才有了对“连续空间”的一些疑问
    zhao1014
        25
    zhao1014  
    OP
       2020-11-07 20:23:54 +08:00
    @systemcall 今天了解了一下关于存储器的知识:“内存与磁盘的动态交换。操作系统将正在使用的部分保存在内存中,其他部分留在磁盘,在需要时再从磁盘中读取,不用的数据再返回给磁盘。”

    我感觉虚拟存储器好像跟大家说的虚拟内存不是一回事,虚拟存储器就是我们使用 Windows 系统时可以设置的虚拟内存,大家提到的“虚拟内存”似乎是对物理内存的一种封装?本质上是一层逻辑?我这样想是对的吗?
    zclHIT
        26
    zclHIT  
       2020-11-07 20:33:05 +08:00   1
    赞一下楼主,之前自己也没有仔细思考过这个问题,看了大家的讨论才恍然大悟,不说了我也去翻《操作系统》去了。。。
    Huelse
        27
    Huelse  
       2020-11-07 21:25:03 +08:00
    段页式内存管理,这个是操作系统维护的,而且有专门的寄存器来映射地址

    这个是操作系统中内存管理的基础
    AV1
        28
    AV1  
       2020-11-07 21:55:20 +08:00   1
    外行人眼中:
    虚拟内存=页面文件

    计算机专业里:
    虚拟内存=物理内存+页面文件(linux 下叫交换区)

    由此可见,所谓的虚拟内存,是对多种存储介质的一层封装。
    对应用程序来说,它们都是在虚拟内存里工作的,并不需要关心自己到底在物理内存里还是页面文件里。至于决定它们要运行在物理内存里还是页面文件里,那时操作系统的工作。

    如果你使用的是 win10 、win8 操作系统,可以打开任务管理器->性能标签->内存,仪表盘下面有个“已提交”,表现为类似 数字 A / 数字 B 形式。这里体现的就是虚拟内存(计算机专业里)的使用状态,数字 A 是已分配给程序的虚拟内存,数字 B 虚拟内存总大小大致就是你的内存+设置的页面文件大小。

    生活中常常看到有人抱怨,“明明可用内存还有那么多,系统却提示内存不足了”,那是因为他们只留意物理内存还有可用空间,但实际上 windows 是根据虚拟内存(上述的“已提交”)来判断内存不足的,这时候就要通过增大页面文件大小,才能缓解“内存不足”。
    temp178
        29
    temp178  
       2020-11-07 22:09:43 +08:00
    @winglight2016 需要连续空间的。比如数组。或者成员变量比较多的对象,需要的空间也大一些
    zhao1014
        30
    zhao1014  
    OP
       2020-11-07 22:35:21 +08:00 via Android
    @DOLLOR 感谢!
    quanjw
        31
    quanjw  
       2020-11-07 22:52:16 +08:00
    《程序员的自我修养链接、装载与库》 emmm 其实我也没看完,但是你这个问题 我有看到过解释
    winglight2016
        32
    winglight2016  
       2020-11-08 11:08:57 +08:00
    @mejee 你说的是那种原生类型的数组吧,那种 element 都不是对象,连续存储就比较方便,但是也依然可以分开存储。

    @zhao1014 对象不需要连续存储不代表一定要分开存储,也不代表 JVM 全部不需要连续存储。而且 JVM 维护的空闲内存列表和运行时产生的内存分配略有不同,JVM 是负责 java 程序和 OS 之间的交互层,所以 java 内部的内存管理和 OS 的内存没什么直接的关系。所以,连续内存最大的好处在于提高存储效率,减少读写时间,然而因为 GC 机制,内存碎片化难以避免。
    systemcall
        33
    systemcall  
       2020-11-08 12:15:09 +08:00 via Android   1
    @zhao1014 虚拟内存不仅仅是含有物理内存,还有页面文件,甚至有些地址根本没分配内存
    而且,如果是 32 位的 Windows,进程空间只有 2G,这 2G 也没有都分页,也只有一部分页在物理内存。一些文章介绍的很详细。
    m30102
        34
    m30102  
       2020-11-08 14:00:53 +08:00
    听过 4k 对齐吗? mmu 管理的最小单位就是 4k
    Junzhou
        35
    Junzhou  
       2020-11-08 20:52:21 +08:00
    看来你跟我一样,操作系统的知识都还给老师了。
    xx6412223
        36
    xx6412223  
       2020-11-09 09:46:39 +08:00
    任何进程的内存都可以是物理不连续的,或者说不连续才是正常情况。不是面试想了解 jvm 还是建议先看 Linux 内存管理
    zhao1014
        37
    zhao1014  
    OP
       2020-11-09 10:58:18 +08:00 via Android
    @xx6412223 虽然是为了应对面试,但还是想理解清楚 XD,会继续深入学习的
    xingguang
        38
    xingguang  
       2020-11-09 11:03:15 +08:00
    本来物理内存是否连续和逻辑内存是否连续就没关系的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     952 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 23:39 PVG 07:39 LAX 15:39 JFK 18:39
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86