简体   繁体   English

java:类成员的内存如何分配?

[英]java: How does the memory of a class member allocate?

We have a big class with 68 int, 22 double members, and there are also 4 members as class. 我们有68个int的大类,22个double成员,还有4个成员。 eg 例如

Class A{

   public int i1

   public int i2

   public int i3

   ....

   public Order order1


   public Order order2

   ...

   public double..

}

1: Is the memory of i1,i2,i3 is continually physically? 1:i1,i2,i3的内存在物理上是连续的吗?

2: For class A, does it store the pointer to order1 & order 2, or it stores the content of order 1 & order 2? 2:对于类A,它存储指向order1和order 2的指针,还是存储订单1和order 2的内容?

There is another class B which has a member as an array of A, there are 365 A. So the memory for B could be very large. 还有另一个类B,该类的成员是A的数组,即365A。因此B的内存可能很大。 My concern is if the size of B is too huge, we can get lots of cache level 2 missing and degrade the performance. 我担心的是,如果B的大小太大,我们可能会丢失很多2级缓存,从而降低性能。 We mainly will sum the value of i1, and sum the value of i2, and sum the value of i3 etc. eg if sum i1 for all 365 A, then the i1 for all these 365A will not sit continually in the memory. 我们主要将对i1的值求和,对i2的值求和,对i3的值求和,例如,如果对所有365 A求和i1,那么所有这些365A的i1将不会连续地位于内存中。 So we could hit some cache missing and get not good performance. 因此,我们可能会丢失一些缓存,从而导致性能不佳。

I am thinking of using class B but remove the class A, and move all the elements inside A to B, so we can get 我正在考虑使用类B,但删除类A,并将A中的所有元素移到B,这样我们就可以

Class B {

   public array_of_i1

   public array_of_i2
..

}

In this way, when I calculate the sum of i1 or i2, then all the i1 or i2 are sitting together, so maybe we could get performance improvement? 这样,当我计算i1或i2的总和时,所有i1或i2都坐在一起,那么也许我们可以提高性能?

As the class is huge, I'd like to look for your opinions before the change. 由于课程人数众多,我想在变更之前寻求您的意见。

It's generally consecutive but it depends on which JVM you are using. 它通常是连续的,但是取决于您所使用的JVM。

One complication is that runtime in memory structure of Java objects is not enforced by the virtual machine specification, which means that virtual machine providers can implement them as they please. 一种复杂的情况是,虚拟机规范未强制执行Java对象的内存结构中的运行时,这意味着虚拟机提供程序可以根据需要实现它们。 The consequence is that you can write a class, and instances of that class in one VM can occupy a different amount of memory than instances of that same class when run in another VM. 结果是您可以编写一个类,并且在另一台VM中运行时,该同一个类中的该类实例所占用的内存量可以与该同一个类中的实例占用的内存量不同。

As for the specific layout, 至于具体的布局,

In order to save some memory, the Sun VM doesn't lay out object's attributes in the same order they are declared. 为了节省内存,Sun VM不会按照声明对象的顺序来布置对象的属性。 Instead, the attributes are organized in memory in the following order: 而是按照以下顺序在内存中组织属性:

  1. doubles and longs 双打和多头
  2. ints and floats 整数和浮点数
  3. shorts and chars 短裤和短裤
  4. booleans and bytes 布尔值和字节
  5. references 参考资料

(from http://www.codeinstructions.com/2008/12/java-objects-memory-structure.html ) (摘自http://www.codeinstructions.com/2008/12/java-objects-memory-structure.html

He also includes how inherited classes are handled. 他还介绍了如何处理继承的类。

The JLS doesn't strongly specify the exact sizes of objects, so this can vary between JVM implementations (though you can infer some lower bounds, ie an integer must be at least 32 bits). JLS并未严格指定对象的确切大小,因此这在JVM实现之间可能会有所不同(尽管您可以推断出一些下限 ,即整数必须至少为 32位)。

In Sun's JVM however, integers take 32 bits, doubles take 64 bits and object references take 32 bits ( unless you're running on a 64-bit JVM and pointer compression is disabled). 但是,在Sun的JVM中,整数占32位,双精度占64位,对象引用占32位( 除非您在64位JVM上运行并且指针压缩被禁用)。 Then the object itself has a 2 word header, and the overall memory size is aligned to a multiple of 8 bytes. 然后,对象本身具有一个2字的标题,并且整个内存大小与8个字节的倍数对齐。

So overall this object should take 8 * ceil((8 + 68 * 4 + 22 * 8 + 4 * 4) / 8) = 10448 bytes, if I haven't forgotten to account for something (which is entirely possible), and if you're running on a 32-bit machine. 因此,总体而言,如果我没有忘记考虑某件事(完全有可能),则此对象应占用8 * ceil((8 + 68 * 4 + 22 * 8 + 4 * 4) / 8) = 10448个字节,并且如果您在32位计算机上运行。

But - as stated above, you shouldn't really rely too strongly on this as it's not specified anywhere, and will vary between implementations and on different platforms. 但是 -如上所述,您不应真正依赖它,因为它没有在任何地方指定,并且在实现和不同平台上有所不同。 As always with performance-related metrics, the key is to write clean code, measure the impact (in this case use a profiler to look at memory usage, and execution time) and then optimise as required. 与使用性能相关的指标一样,关键是编写干净的代码,衡量影响(在这种情况下,使用探查器查看内存使用情况和执行时间),然后根据需要进行优化。

Performance only really matters from the macro perspective; 从宏观角度来看,性能才是真正重要的。 worrying about L2 cache misses when designing your object model is really the wrong way round to do it. 在设计对象模型时担心二级缓存丢失确实是错误的做法。

(And a class with 94 fields is almost certainly not a clean design, so you're right to consider refactoring it...) (而且具有94个字段的类几乎肯定不是一个干净的设计,因此您应该考虑对其进行重构...)

Firstly, before you embark on any work, have you profiled your application? 首先,在您从事任何工作之前,您是否已对应用程序进行了概要分析? Are cache misses causing a bottleneck? 缓存未命中是否会造成瓶颈?

What are your performance requirements? 您对性能有何要求? (Note: 'As fast as possible' isnt a requirement*) (注:“越快越好” 心不是要求*)

  1. That would be implementation dependent. 那将取决于实现。
  2. Yes, it stores pointers. 是的,它存储指针。 The objects will reside elsewhere. 这些对象将驻留在其他位置。
  1. In general, yes. 一般来说,是的。 But I don't think you necessarily want to depend on it. 但我认为您不一定要依赖它。 Wrong language for that low-level type stuff. 该低级类型内容的语言错误。
  2. Pointers, but I'm not sure why that matters. 指针,但是我不确定为什么这么重要。
  3. Profile before making significant changes for performance reasons. 由于性能原因,在进行重大更改之前进行配置。 I think the second is cleaner though. 我认为第二个虽然干净 Wouldn't you rather do a simple array loop for your summing? 您是否愿意为求和做一个简单的数组循环?

Or you could change the structure to use a smaller class, keeping the stuff that runs in a tight loop together will tend to improve cache hits (iff that is your performance bottleneck). 或者你可以改变使用较小的类结构,保持在一个紧凑的循环运行起来往往会提高缓存命中率(IFF这是你的性能瓶颈)的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM