当前位置: 首页 > 知识库问答 >
问题:

当在多个容器中存储数据时,Java的参考系统是否有助于节省内存?[副本]

曹高阳
2023-03-14

考虑这个对象:

Person alice = new Person("Alice", 0);

它被添加到两个ArrayList中:

ArrayList<Person> foo = new ArrayList<Person>();
ArrayList<Person> bar = new ArrayList<Person>();

foo.add(alice);
bar.add(alice);

此时,堆内存中是否有三个Person对象(每个ArrayList中加一个)?或者内存中是否有一个Person对象以及指向它的三个引用(指针)?

Person对象有两个字段,一个字符串和一个int。假设我有许多Person对象,我想让它们在不同的时间以两种不同的方式进行排序(有时按字符串的字母顺序,有时按int的数字顺序)。

这似乎可以通过两种方式实现:

>

  • 有一个容器,如ArrayList,对象并在我想更改排序方案时按需排序

    有两个容器,一个按字符串字母顺序对人员进行排序,另一个按整数进行排序

    第一种方法是时间效率低,但空间效率高。

    第二种方法是时间效率高,但空间效率低(例如,人对象非常大)。

    在像C这样的语言中,在时间和空间上高效地执行这一操作需要第二种方法,但需要使用指向单个Person对象集合的多个指针容器。因为这很困难,人们通常会推荐像Boost的multi\u index\u容器这样的东西,它正好做到了这一点。在Java中,我看到人们消除了这种复杂性,这似乎是可能的,因为所有Java对象都在指针式引用之后。

    他们这样做正确吗?在Java中,以节省空间的方式进行第二种操作是否与使用多个容器对相同对象进行冗余引用一样简单?

    这在其他语言中是真是假,例如JavaScript、Python、Ruby、C#、Go、Rust等?

  • 共有1个答案

    贲宏硕
    2023-03-14

    此时,堆内存中是否有三个Person对象(alice加上每个ArrayList中的一个)?

    内存中的一个Person对象,具有三个对象引用(指针)。您声明的Person alice变量保存一个引用,而您创建的每个List保存一个对象引用(指针)的单个元素。所以总共有3个引用。

    从技术上讲,ArrayList是对象引用(指针)列表,而不是对象列表。当我们说数组列表时

    需要理解的棘手部分是,Java语法是故意设计的,目的是对Java程序员隐藏引用/指针。这为我们在日常编程工作中将List视为包含Person对象提供了便利。我们知道底层结构实际上是引用/指针,但我们不需要考虑这些。

    从列表中检索人员时:

    Person p = foo.get( 0 ) ;  // Annoying zero-based index counting. So zero is the first element.
    

    ...Java访问列表中的元素,获取其存储的引用/指针,然后跟随该引用/指针查找该对象在内存中的位置,并返回要存储的内存位置(基本上是一个数字)在本例中名为p的引用-to-a-Person-ject变量中。

    当我们从Person对象中获取名称成员时:

    String name = p.name ; 
    

    ... JVM遵循存储在p中的引用/指针来定位在内存中其他地方浮动的实际对象,然后在该内存块中移动以找到name成员变量对象。

    相比之下,C语言使这些指针非常明显且可用。这使得编程更加混乱和复杂,更容易出错。

    在开始编程时,您不需要了解所有这些。偶尔重温一下这个话题,仔细考虑一下,最终它会变得有意义。图表可以提供帮助。有关更多信息和图纸,请参阅我对相关问题的一些回答,这里和这里。搜索堆栈溢出,因为此主题已在此处和此处多次讨论。

    使用Java集合框架,您有两个选项可以按排序顺序访问一组对象:切换顺序时重新排序,或者维护两个集合。对象中内容的大小无关紧要,因为集合中只涉及指针。

    当然,第三方可以自由开发自己的收藏来展示其他行为。

     类似资料:
    • 我使用一个java jdbc应用程序从DB中获取大约500,000条记录。使用的数据库是Oracle。当每一行被取出时,我就将数据写入文件。由于获取整个数据需要大约一个小时,所以我尝试增加结果集的获取大小。我在多个链接中看到,在增加读取大小的同时,应该小心内存消耗。增加读取大小实际上会增加jvm使用的堆内存吗?< br >假设提取大小为10,程序查询总共返回100行。在第一次提取期间,结果集包含1

    • 问题内容: 我正在使用Java JDBC应用程序从数据库中获取约500,000条记录。使用的数据库是Oracle。取出每一行后,我立即将数据写入文件。由于完成整个数据的获取大约需要一个小时,因此我试图增加结果集的获取大小。我已经在多个链接中看到,在增加访存大小的同时,应该注意内存消耗。增加获取大小实际上是否会增加jvm使用的堆内存? 假设获取大小为10,并且程序查询总共返回100行。在第一次读取期

    • 主要内容:程序员的幽默计算机要处理的信息是多种多样的,如数字、文字、符号、图形、音频、视频等,这些信息在人们的眼里是不同的。但对于计算机来说,它们在内存中都是一样的,都是以二进制的形式来表示。 要想学习编程,就必须了解二进制,它是计算机处理数据的基础。 内存条是一个非常精密的部件,包含了上亿个电子元器件,它们很小,达到了纳米级别。这些元器件,实际上就是电路;电路的电压会变化,要么是 0V,要么是 5V,只有这两种电压。

    • 问题内容: 我阅读了JVM内存模型,并对以下内容感到困惑: JVM是否将.class实例存储在其内存中。如果是,则在哪个区域。 就像在加载类后,JVM生成了机器级代码,然后开始执行机器代码指令,然后仅在堆上创建对象,并填充了方法区域。 perm gen等区域存储字节码还是机器级代码? 烫发与方法面积 我真的很感谢您对此主题的任何帮助。 谢谢。 问题答案: 1)文件将在加载时存储在permgen存储

    • 我刚开始使用firebase作为我的Flatter应用程序的后端,我有一个问题:如何将两个文档链接在一起,同时获取这两个数据。例如,我有一个用户集合和一个帖子集合。我如何链接这两个文档,当我获取帖子数据时,我也会在相同的响应中获取用户数据

    • 问题内容: 我有一些产品数据需要在Redis缓存中存储多个版本。数据是JSON序列化的。获取纯(基本)数据的过程非常昂贵,将其自定义为不同版本的过程也很昂贵,因此我想缓存所有版本以尽可能进行优化。假设自定义基于单个参数,我可以将该参数用作缓存键的一部分。 我计划用来检索产品数据的过程是这样的: 一切都很好,但是我现在正在尝试找出在基础数据源发生更改时使缓存数据无效的最佳方法。如果基本产品信息发生变