2009-10-05 47 views
9

由於RAM似乎爲the new disk,並且由於該語句也意味着訪問內存現在被認爲是緩慢的,類似於磁盤訪問一直如此,所以我確實希望最大化內存中對高性能應用程序的引用的位置。例如,在排序索引中,我希望相鄰值相近(不同於在散列表中),並且我也希望索引指向的數據也靠近。在C中,我可以使用專門的內存管理器抽取數據結構,就像(非常複雜的)開發人員一樣。通過直接控制指針,它們甚至可以在指針值本身編碼附加信息。當使用Python,Java或C#工作時,我故意從這種類型的解決方案中抽象出一個(或多個)級別,並且我委託JIT編譯器並優化運行時間,爲我做低級別的巧妙技巧。在託管代碼中,如何實現良好的引用位置?

不過,我想,即使是在這樣高層次的抽象,有可語義認爲是「接近」,因此很可能是實際上接近在低水平的東西。例如,我想知道以下內容(我在括號中的猜測):

  • 我可以期待一個數組是相鄰的內存塊(是)嗎?
  • 同一個實例中的兩個整數在相同類的不同實例中可能比兩個更接近(可能)?
  • 對象在內存中是否佔用連續區域(否)?
  • 僅有兩個int字段的對象數組與兩個int[]字段的單個對象之間的區別是什麼? (這個例子可能是特定於Java)

我開始懷疑這些在Java方面,但我的疑惑變得更加普遍,所以我建議不要把這個作爲一個Java的問題。

+0

此外,緩存是新的CD-ROM ......並且您現在依賴於您的性能的內部實現細節。一個到.NET的服務包,改變事情在幕後工作,你的整個堆棧崩潰... – wefwfwefwe 2009-10-05 16:57:09

+0

@wefwfwefwe:你的觀點是 - 究竟是什麼?即使Hanno的問題的答案沒有被任何標準保證,如果你真的需要優化,你必須使用_something_來優化。 – hjhill 2009-10-05 20:08:20

+0

關鍵是,你可能會通過試圖超越.net/java開發人員來解決他們應該爲你做的事情。 – wefwfwefwe 2009-10-06 07:30:49

回答

8
  • 在.NET中,數組的元素當然是連續的。在Java中,我希望它們在大多數實現中,但似乎並不能保證。
  • 我認爲這是合理的假設由實例使用的內存字段在一個塊中......但不要忘記,其中一些字段可能是其他對象的引用。

對於Java陣列的一部分,包括Sun's JNI documentation此評論,在關於字符串的討論侷促:

例如,Java虛擬機可以不存儲陣列連續。

爲了您的最後一個問題,如果你有兩個int[]然後每個這些陣列將是一個連續的內存塊,但他們可能是很「遙遠」在內存中。如果你有一個包含兩個int字段的對象數組,那麼每個對象可能相距很遠,但是每個對象內的兩個整數將靠近在一起。可能更重要的是,由於每個對象的開銷,最終你會因爲「大量對象」解決方案而帶來更多的內存空間。在.NET中,你可以用一個自定義的結構來代替兩個整數,並且有一個這樣的數組 - 可以將所有數據保存在一個大塊中。

我相信在Java和.NET中,如果你在一個線程內快速連續地分配很多小對象,那麼這些對象可能是,可能具有良好的引用位置。當GC壓實堆,這可以提高 - 或者它可以潛在地變得更壞,如果與

A B C D E 

堆被壓縮到

A D E B 

(其中被收集C) - 突然甲乙,之前可能已經「接近」,相隔甚遠。我不知道這是否真的發生在任何垃圾收集器(有周圍的負載!),但它是可能的。

基本上,在一個託管環境中,通常不會像在非託管環境中那樣對引用的局部性有太多控制權 - 您必須相信託管環境對管理環境足夠好,並且您會通過編碼到更高級別的平臺節省了足夠的時間,讓您花時間在其他地方優化。

+2

你確定Java數組是連續的嗎? 儘管大多數虛擬機可能會在連續的內存塊中分配Java數組,但我無法在語言或虛擬機規範中找到對此的任何要求。如果保證連續塊,用於訪問數組的JNI函數看起來相當多餘,因爲可以將指向內存的指針傳遞給本機函數。 – jarnbjo 2009-10-05 09:30:11

+0

不錯的答案,但... 。只需從託管堆的底部(或頂部)抓取一塊連續內存,即可爲對象分配內存。所以obujects成員變量總是會在RAM中相鄰的。但是,對於參考類型,這意味着指針是相鄰的。它指向的位置將取決於它指向的對象何時構建。一個數組是一個對象,所以同樣適用於數組元素是其成員的數組。 – pipTheGeek 2009-10-05 09:46:05

+0

@pip:我想我已經涵蓋了所有這些,不是嗎? (請參閱我的第二個項目符號。) – 2009-10-05 09:58:36

3

首先,您的標題暗示C#。如果我沒有弄錯,「託管代碼」是微軟創造的一個術語。

Java基元數組保證是一個連續的內存塊。如果你有一個

int[] array = new int[4]; 

你可以從JNI(本機C)獲得int *p指向實際的數組。我認爲這也適用於Array *類的容器(ArrayList,ArrayBlockingQueue等)。

JVM的早期實現具有連續結構的對象,我認爲,但這不能用較新的JVM假定。 (JNI把這個抽象出來)。

同一個對象中的兩個整數會像你說的那樣「接近」,但它們可能不是。即使使用相同的JVM,這可能會有所不同。

有兩個int字段的對象是一個對象,我不認爲任何JVM都會保證成員將「關閉」。具有兩個元素的int數組很可能會由一個8字節長的數組支持。

+0

jarnbjo和Jon Skeet在Jon的回答中討論了Java數組,並得出結論認爲它們可能但不能保證是連續的。 JNI中的原始類型與引用類型的數組有區別嗎? – 2009-10-05 13:04:06

+0

「託管代碼」是一個術語,用於表示在託管環境中運行的任何語言 - 即JVM或.NET框架。 MS使用它比大多數用來區分它和Windows的本地編碼,而Java不需要做出這樣的區分。 – gbjbaanb 2009-10-05 13:34:47

+0

我從來沒有聽說過.NET領域之外的術語「託管代碼」。在.NET出現之前,Java人員談論了JVM和字節碼,而不是託管代碼。 – JesperE 2009-10-05 15:42:53

2

至於這裏陣列是從CLI(公共語言基礎結構)規範的摘錄:

數組元素應以行優先 順序進行佈局 陣列對象內(即,元件相關聯 與最右邊的陣列維度 應從最低指數到最高指數連續佈置)。爲每個 數組元素分配的實際存儲可以包括 平臺特定的填充。 (大小此存儲的 ,以字節爲單位,由sizeof運算指令,當它被應用到陣列的 元素的類型 返回 。

2

問得好!我想我會訴諸編寫擴展中C++以更謹慎的方式處理內存,並且暴露足夠的接口以允許應用程序的其餘部分操作對象。如果我關心性能,我可能會採用C++擴展。

+0

不錯的建議,特別是因爲它可以讓你在多種VM語言之間移植你的解決方案。但是,當然,這種方法很容易涉及大量的工作,然後可以非常方便地瞭解更多關於在當前環境中可以做什麼的信息。 – 2009-10-05 12:54:21

+0

另請參閱我對Nick Craig-Wood關於Python的文章的評論 - 許多高級語言將提供試圖仿效某種低級功能的庫,只要不浪費太多,它們可能會提供類似的好處CPU時間轉換數據進出。 – Kylotan 2009-10-05 13:29:26

-3

如果您需要優化自己的水平,那麼我懷疑一個基於虛擬機的語言是不適合你;)

+4

這當然是一個簡單的答案,但幾乎沒有什麼有趣的。選擇一個特定項目的語言是一個有多種因素的決定,其中包括性能,但並不總是最重要的一個。當你真的需要*來優化到這個水平是一個同樣複雜的決定。你可以在大鐵上走很長的路,你可以嘗試獲得更多的可伸縮性,並添加更多的機器等。但是如果你知道什麼/可能/確實不會改善你正在使用的語言的參考地點,這只是給你更多的建築磚塊解決方案。 – 2009-10-05 12:49:16

+0

無論如何。如果您想微觀管理內存,請使用手動管理內存的語言。 – wefwfwefwe 2009-10-05 15:28:46

2

我不認爲任何人談論的Python,所以我將有一個去

我可以期待一個數組是一個相鄰的內存塊(是)嗎?

在python數組更像是C中指針的數組。因此指針將相鄰,但實際的對象不太可能是。

同一個實例中的兩個整數在相同類的不同實例中可能比兩個更接近?

可能與上述原因不一樣。該實例只保存指向實際整數對象的指針。 Python沒有本地int(像Java),只有盒裝Int(用Java說話)。

對象是否在內存中佔據連續區域(否)?

可能不是。但是,如果您使用__slots__優化,那麼它的一些部分將是連續的!

只有兩個int字段的對象數組和兩個int []字段的單個對象數組之間有什麼區別? (這個例子可能是Java特定的)

在python中,就內存的局部性而言,它們幾乎都是一樣的!一個會創建一個指向數組的指針數組,其中包含兩個指向int的指針,另一個指向兩個指向整數的指針數組。

+0

太好了,謝謝!我認爲在這裏積累一些有關VM語言的信息會很酷。 – 2009-10-05 12:55:40

+1

我認爲這有點誤導,因爲Python本身並沒有數組,只是列表,如上所述,這將是一個指向PyObjects的指針數組。但是它也提供了一個數組模塊(http://docs.python.org/library/array.html)和一個結構模塊(http://docs.python.org/library/struct.html),每個模塊都會給你更密切和可預測的打包數據。 – Kylotan 2009-10-05 13:27:34

+0

@Kylotan你當然是對的 - 我試圖將問題的Java面向性轉化爲正常的Python使用。如果你想獲得更好的內存局部性,數組模塊將非常值得一看。 – 2009-10-05 21:31:05