前言
最近,复习中,突然发现有一个知识点之前遗漏了。主要让我产生疑问的是如下问题:
- 2^32 = 4G。
- 建议JVM内存不要超过32G。
- JVM内存超过32G,压缩指针失效。
- 前置知识:Java对象布局(内存模型/结构)
- 解惑学习的两篇博客:聊一聊JAVA指针压缩的实现原理(图文并茂,让你秒懂)、32位CPU最多支持4G内存是怎么算出来的?
一、压缩指针是什么?
压缩指针,其实可以分为压缩和指针两个概念。
- 压缩:就是将一个体量比较大的东西,变为体量较少的一种操作,所以也可以理解为使用一个体量较小的东西,来表示一个体量大的东西,当然两者表达的含义不能被修改或者丢失。
- 指针:指针也就是内存地址,指针变量是用来存放内存地址的变量。也可以这样理解,指针就是指向某个地方,作用就是告诉计算机,当前引用所指向的对象在内存中的地址。
- 压缩指针:两个概念组合之后含义就是将指针进行压缩;作用就是将原本需要很多指针才能标识的内存空间,使用较少的指针进行标识。
二、压缩指针如何实现?
计算方法
其实还是比较好理解的,可以有这样一个计算方式:M = N * S 。
- M:可以支持的最大内存。
- N:内存地址个数。
- S:每个地址指向的内存空间大小。
即:支持的内存大小 = 内存地址个数 * 每个地址指向的内存空间大小。
所以,提高M的上限就有两种方式:
- N的大小一定时,我们可以通过增加S的大小提高M。
- S一定时,增加N的大小也可以提高M。
其实讲到这里,如果大家对于Java中对象的布局(内存模型或组成)了解的话,应该就很清楚了。Java对象头中有一个东西叫做klasspoint,这个就是压缩指针,不清楚的小伙伴可以点击文章前言中的前置知识链接进行简单了解。
4个字节 = 32bit,所以能表示的内存地址个数为2^32个,也就是说其实当压缩开启且未失效时,内存地址的个数是一定的,也就是我们上面提到的公式N是一定的。因此,在这样的条件下,提高M的办法就只有增加S的大小一种办法。
那么每个地址指向的内存空间大小是多少呢?
其实这个是我们自己可以规定的,可以是计算机中最小的单位1bit,也可以是IO操作的最小单元1byte,也可以1M,1G等等。
- 那么是越大越好吗?答案当然是否定的,加入现在设定每个地址指向的内存空间大小为1M,这时我创建了一个0.5M的对象,那么是不是就浪费了0.5M的内存?所以,每个地址指向的内存空间大小并不是越大越好,越大浪费越严重。会不会有小伙伴说,那我再创建一个0.5M对象放进去不就不浪费了?这里要有个基本概念,一个指针只能指向一个明确的对象,如果放两个进去,那么引用的到底是哪个对象呢?所以,这样的想法一定是错误的。
- 太大会浪费,那么太小呢?显而易见,不能达到我们增加M的需求,举个例子:我们将每个地址指向的内存空间大小设置为1bit,那么按照M = N * S,可以得到可以支持的最大内存空间为2^32 * 1bit = 2^32bit = 2^29byte = 2^19KB = 2^9M = 2^-1G = 0.5G, 那么经常说出 2^32 = 4G是怎么来的呢?4/0.5 = 8,咦?是不是有点意思,也就是说每个地址指向的内存空间大小是8bit = 1byte,实际上内存是把8个bit排成1组, 每1组成为1个单位, 大小是1byte(字节)。这也就解决了我第一个疑惑。
Java中是如何设置
那么Java是使用1byte作为每个地址指向的内存空间大小吗?这里我们可以从两种思考方式:
- 反向推理:JVM内存超过32G,压缩指针就会失效,32/4=8(这里的4即为4G = 2^32),也就是说,如果开启压缩指针的上限为32G,那么每个地址指向的内存空间大小应该是8byte。
- 正向理解:Java是面向对象编程,Java中每个对象的大小都是8byte的整数倍,因此Java使用8byte作为每个地址指向的内存空间大小也肯定没有问题,不会出现两个对象内容出现在同一个8byte内存块内,避免一个指针指向多个对象的问题。
是不是很巧,哈哈哈。这也就解决了,我第二、第三的疑惑。
总结
以上就是今天要讲的内容,本文是个人学习后,个人进行的总结分析,如不能理解可以查看引言中解惑文章进行详细学习。
版权声明:本文为m0_37670016原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。