不安全的代码: 教你“随心所欲”地在内存中操作Java的类和对象(2)

本文探讨了Java中对象表示方法——OOPs与CompressedOOPs的区别与联系,介绍了CompressedOOPs如何通过32位对象偏移表示64位的字节偏移,从而在64位系统中有效利用内存,节省空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面的话:译者本身能力有限,不能逐字逐句地翻译。本人翻译的目标是为了能给大家说得简单明了,所以会采取意译的方法。如果有措辞不正确或不好的地方,讲大家不吝赐教,谢谢!

原文地址:https://zeroturnaround.com/rebellabs/dangerous-code-how-to-be-unsafe-with-java-classes-objects-in-memory/2/

OOPs 与 Compressed OOPs

每一个Java对象在堆中被表示为一个普通对象指针(Ordinary Object Pointer,OOP)。每个OOP是一个指向Java堆内空间的一个受管理(控制)的指针。指向的空间是Java进程内的虚拟地址表示的一块连续的空间。

一般情况下,OOP的大小与宿主机的指针一样,也就是说在LP64数据模型系统中,OOP的大小是64位的。在一个ILP32数据模型系统中,堆的最大空间要小于4G。这有点小,对于很多应用来说不够用。

OOP指针指向的Java对象在堆中是以8字节地址边界对齐的。Compressed OOPs(压缩过的指针——好土的名字吧,请原谅笔者的翻译,水平有限呀)在Java虚拟机的堆中,很多时候(而不是所有情况都是),用32位的对象位移(object offset)来表示64位的字节位移(byte offset)[笔者认为,这句话可以认为:用32位的对象指针来替代64位对象指针]。因为Compressed OOP中的offset(笔者认为翻译成“位移”反而更让人搞不懂)是object offset,而不是byte offset。32位的object offset可以寻址的范围是4,000,000,000*objects*,也就是32GB的堆内空间。[在这里作者说得很让人发晕,不过笔者认为他就说了一件事儿:以前普通对象指针是按字节计算对象在内存中位置的,而现在Compressed OOPs则是按8字节为单位计算的。这也是为什么32位字节的指针本来只能寻址4GB的空间,现在就达到32GB了。实现这个技术的基础就在于段落第一句,因为Java对象在64位机器中是以8字节地址边界对齐的。] 为了能够正确找到对象的位置,Compressed OOPs的值需要乘以8再加上Java堆的基址才可以。使用compressed OOPs技术的对象的大小和在ILP32模式下的对象大小一般大。

Compressed OOP在Java v6u23及以后的版本中默认是打开的。在Java7中,在64位JVM中若启动java进程时”-Xmx”没有指定值或者其值小于32GB时,Compressed OOP技术是默认打开的。JDK6中6u23之前的版本需要在启动Java进程中添加“-XX:+UserCompressedOops”选项才能够使用这个特性。具体见这个链接:(http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html


先简单地说下SampleClass

在这篇文章中,我们将用一个样本类——SampleClass,正如其名一样是个样例——为例来探索下其对象访问、其属性地layout(部局)等等。这个类很简单,其包含3个基本类型变量,并且继承SampleBaseClass类以说明继承反映在内存layout上是什么样子的。类的定义如下(这些类的代码也可以在github上找到):

public final class SampleClass extends SampleBaseClass {

    private final static byte b = 100;

    private int i = 5;
    private long l = 10;

    public SampleClass() {

    }

    public SampleClass(int i, long l) {
        this.i = i;
        this.l = l;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public long getL() {
        return l;
    }

    public void setL(long l) {
        this.l = l;
    }

    public static byte getB() {
        return b;
    }
}
public class SampleBaseClass {

    protected short s = 20;
}

To Be Continued…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值