【问题标题】:storing an object reference in byte array在字节数组中存储对象引用
【发布时间】:2012-09-16 13:14:42
【问题描述】:

我有一个字节数组和一个对象引用。

    byte[] data = new byte[128];

    Block b = new Block();

我想将引用 b 存储在 "data" 数组的最后 2(或 4)个字节中。

请注意:我不想序列化对象并存储在字节数组中。我需要存储一个指向新块的指针(引用)。

编辑

我的Block类如下

    public class Block {
        byte[] data ;

        public Block(){
            data = new byte[128];
        }
}

基本上,数据数组将使用 126 字节来存储字符串,最后两个(或 4)字节来存储对另一个块的引用。它是一种链接列表。

我本可以使用 Block 类的不同定义来完成它[通过在类本身中包含对 Block 的引用]。但是问题陈述指出了只有最后 2 个字节应该用作对另一个块的引用的约束。从其他帖子我知道在 jvm(32 位)中,引用的大小为 4 个字节。因此我认为只能使用最后 4 个字节来完成

问题陈述片段

块的最后 2 个字节用于指向下一个块。 假设文件大小为 8 个块,那么第 4 个字节的最后 2 个字节 block 将指向第 5 个块,第 5 个块的最后 2 个字节指向 第 6 块,依此类推。

【问题讨论】:

  • 我相信你不能得到一个对象的引用地址。
  • 你打算用那个 2/4 字节的引用做什么?
  • 请说明您将如何处理字节数组。如果您通过套接字或 IPC 将其发送到文件或其他应用程序,那么在该运行进程中保留仅对应用程序本身有意义的引用是没有用的。
  • @E_net4 使用问题陈述中的 sn-p 编辑问题
  • @PeterLawrey :-D 我不确定拼图的年龄。但是在阅读了这里的帖子之后,我非常有信心在我的类定义中使用对块的引用

标签: java arrays memory byte object-reference


【解决方案1】:

基本上,数据数组将使用 126 字节来存储字符串,最后两个(或 4)字节来存储对另一个块的引用。它是一种链接列表。

您可以通过存储块索引来做到这一点。

例如

// list of blocks so you can lookup any block using a 16-bit index.
List<Block> blocks = new ArrayList<Block>();

int indexInBlocksToNext = ...
data[126] = (byte) (indexInBlocksToNext >> 8);
data[127] = (byte) indexInBlocksToNext;

我可以使用 Block 类的不同定义来完成它[通过在类本身中包含对 Block 的引用]。但是问题陈述指出了只有最后 2 个字节应该用作对另一个块的引用的约束。从其他帖子我知道在 jvm(32 位)中,引用的大小为 4 个字节。因此我认为只能使用最后 4 个字节来完成

所有 32 位系统都使用 32 位指针或引用。您不能在 Java 中放置引用,因为没有通过数字引用对象的全局方式。您可以获取对象在内存中的位置,但此位置可以随时更改。


使用 Java 7 之前使用的最小内存约为 1.3 MB。

$ java -mx1200k -version
Error occurred during initialization of VM
Too small initial heap for new size specified
$ java -mx1300k -version
java version "1.7.0_05"
Java(TM) SE Runtime Environment (build 1.7.0_05-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.1-b03, mixed mode)

这意味着您在计划开始之前就已经使用了超过 1 MB 的预算。

【讨论】:

  • +1 You can obtain where an object was in memory ummm,这怎么能在 Java 中完成?
  • 您可以使用 JNI 或 sun.misc.Unsafe 获取引用,如 intlong 值以查看其位置,但这只会告诉您它的位置,因为当您有数字时它可能已经改变了。对于 64 位 JVM,它并没有真正告诉您绝对位置,因为它使用 32 位引用来获取高达 32 GB 的内存,并且可以使用诸如 reference * 8 + offset 之类的翻译来获取内存中的实际位置。
  • 但说真的,你永远不应该这样做。
  • 你不应该相信你有必要这样做。 ;)
【解决方案2】:

您可以通过ObjectOutputStream 序列化任何对象(请注意,您必须将implements Serializable 添加到您的类Block)。例如:

Block block = new Block();
// ...
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(new File("test.dat"))));
oos.wrtieObject(block);
oos.close();

然后像这样读:

ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("test.dat"))));
Block block = (Block) ois.readObject();
ois.close();

【讨论】:

  • 我以为他问的就是这个。
  • 它将如何提供帮助?我将如何处理序列化对象。我不想将对象存储在字节数组中。我想将对象引用存储在字节数组中。
  • 有什么用?我很确定可以使用某种界面或语言机制来完成。
  • 您将无法以干净的方式做到这一点。即使你这样做了,你也无法用它做很多事情。不过,这可能会有所帮助,请阅读此文档。 grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
  • @AnupamGupta 正如 iccthedral 提到的,您无法访问对象的引用地址(内存位置)!至少不是在 Java 中:)
【解决方案3】:

我需要存储一个指向新块的指针(引用)。

基本上,在纯 Java 中根本无法做到这一点。

执行此操作的非纯 Java 方法(使用 JNI 或 Unsafe 类)将为您提供一个无法安全地转回 Java 引用的值。

原因是当 GC 运行时,它通常会将可到达的对象移动到新位置。现在,如果您在正确的引用类型字段、变量或数组槽中引用了一个对象,GC 将找到该引用副本并将其更新为指向该对象的新位置。但是如果引用已经变成了字节或其他东西,那么 GC 就不会知道字节实际上是引用的表示,也不会更新它。因此,您的引用表示为字节现在将指向错误的位置。如果您将其转回参考并尝试使用它,则可能会发生混乱。


您需要找到一种不同的方式来表示这些Block 引用。如果您不愿意自己序列化 Block 对象,那么显而易见的选项是索引或某种类型的 Map 键。在所有情况下,您的数据结构都需要保存垃圾收集器可访问的对象/数组中的真实引用。

【讨论】:

    【解决方案4】:

    我认为你可以做的是:

    1. 第一个序列化块类。
    2. 然后使用类似下面的方法将块对象转换为字节数组。

    ` public byte[] toByteArray(Object obj) {//

        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            oos.close();
            bos.close();
            bytes = bos.toByteArray();
        } catch (IOException ex) {
            System.out.println(ex);
        }
        return bytes;
    

    `

    1. 使用System.arraycopy(src, srcPos, dest, destPos, length) 方法从源对象复制到目标对象。

    【讨论】:

    • 首先,你不能序列化一个类。只有一个对象可以被序列化。请注意,我不需要序列化对象。我需要以字节为单位存储对象的引用。到目前为止(来自其他答案)在 java 中是不可能的
    【解决方案5】:

    这不能用于 java 中的内存数据结构。

    jvm 规范故意模糊对象引用的存储和分配方式,以允许不同的 jvm 实现对它们如何实现垃圾回收等做出不同的选择。

    您可以做的最好的事情(如果在内存中工作)是模拟一个具有大字节数组的地址空间,您将在其中使用数组中的索引作为指针。

    如果在磁盘上工作,情况就不同了,因为基于磁盘的存储可以通过偏移量访问,并且指针有意义,但您的内存数据结构变得无关紧要

    【讨论】:

    • 有一种方法可以通过块内存映射文件来做到这一点(并且只故意存储它)。但是文件指针又是不同的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 1970-01-01
    • 2014-08-11
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多