如何避免大陣
回答
簡短回答:不。數組創建時總是被清零。
如果您的配置文件顯示這是一個主要瓶頸,您可以考慮保留一個數組實例池,每個配置文件的長度要大於n
。問題是你可能需要一個包裝對象來包含數據數組和實際使用的長度,因爲你不能再使用data.length
。
你可以使用ArrayList
什麼的,並建立你的數組,因爲你需要添加元素給它?這將節省初始化時間,如果這是你的問題。
ArrayList<double> x = new ArrayList<double>();
我認爲這是最好的選擇。所有其他答案都需要很多解決方法,這些解決方案也可能會在未來創建更多時間問題。然而,我想知道是否有Java庫創建數組,您必須初始化每個值而不是使用0自動填充? – patrickhuie19 2016-01-03 14:01:05
@Nick Rolando你不能爲原始類型創建ArrayList,比如'double'。相反,您必須使用'ArrayList
這是個壞主意**。通過向其添加元素來增加列表的花費明顯更高,然後將其分配(初始化)爲最初具有合適的大小。另外,如上所述,您不能擁有基元的'ArrayList',所以當元素數量很大時,這種方法也有可能產生大量的內存開銷。 – Dima 2016-01-07 17:23:31
只要聲明「new double [n]」語句,數組就會初始化。沒有辦法繞過它。
如果你這樣做是爲了優化的緣故,那麼我會利用你對過早優化進行讀取。如果你的程序沒有打牆,那麼它不值得優化。而且它不是你應該優化的數組。
您可以使用ArrayList,以節省初始化時間,然後將其轉換爲一個數組,如果你確實需要雙陣列上的工作是這樣的:
List<Double> withoutInitializing = new ArrayList<Double>();
Double[] nowYouConvert = (Double[]) withoutInitializing.toArray();
從Java文檔:
指定者:以正確的順序(從第一個元素到最後一個元素)返回包含此列表中所有元素的數組。
返回的數組將是「安全」的,因爲沒有引用它是由此列表維護的 。 (換句話說,即使列表由數組支持,該方法也必須分配 新數組)。因此調用者可以免費修改返回的數組。
此方法充當基於陣列和基於集合的 API之間的橋樑。
指定者:指定者()在集合
與此相關的問題是,ArrayList訪問速度稍慢,這對我的高性能算法產生巨大影響。 – 2016-01-02 21:08:30
''ArrayList'實際上是由一個數組(對象)支持的,最初由默認的構造函數賦予一些任意常量('DEFAULT_CAPACITY = 10'),然後在每次空間不足時動態地將數組重新分配給更大的數組。所以,如果你真的想要存儲n個條目,你最終會創建O(log(n))個數組,最後一個至少是添加到元素的數量的大小(可能更大)名單。您可以通過調用專門的構造函數或調用'ensureCapacity()'來確保所需的容量,從而避免重新分配。 – 2016-01-07 01:02:06
所以這絕不會避免創建**並初始化**一個大數組。更不用說,你會讓Double對象在數組中包含double值而不是直接double值,考慮到wrapper對象的開銷,在內存使用方面更糟糕。 – 2016-01-07 01:03:03
一些解決方法如何不初始化數組。
創建一個數組,該數組保證大於最大可能數量的條目並部分填充它。
例如,您可以決定用戶永遠不會提供超過100個輸入值。然後分配尺寸100的陣列:
final int VALUES_LENGTH = 100;
double[] values = new double[VALUES_LENGTH];
然後保持伴侶變量,告訴如何在陣列中許多的元素被實際使用。
int valuesSize = 0;
現在values.length是數組值的能力,和valuesSize
是陣列的當前大小。不斷添加元素到數組中,每次增加valuesSize
變量。
values[valuesSize] = x;
valuesSize++;
這樣,valuesSize
始終包含正確的元素數。 以下代碼段顯示如何將數字讀入部分填充的 數組。
int valuesSize = 0;
Scanner in = new Scanner(System.in);
while (in.hasNextDouble()) {
if (valuesSize < values.length) {
values[valuesSize] = in.nextDouble();
valuesSize++;
}
}
在該循環結束時,valuesSize
包含數組中元素的實際數量。
例如,這裏是你如何讀取任意長的序列號爲 數組,而不會耗盡空間:
int valuesSize = 0;
while (in.hasNextDouble()) {
if (valuesSize == values.length) {
values = Arrays.copyOf(values, 2 * values.length);
}
values[valuesSize] = in.nextDouble();
valuesSize++;
}
像其他人已經提到的,簡單的答案是:不,你無法避免初始化部分。除非您正在使用某些native
分配或使用IntBuffer創建作爲byte buffer的視圖,否則在直接使用字節緩衝區時將是直接的。
如果您沒有使用它們,那麼爲了儘可能快地分配和初始化陣列,您需要最大限度地減少GC
調用,並且必須確保JVM具有存儲和使用所需的內存該數組。
在Albert Hendriks的案例中:static int[][] lookup = new int[113088217][2]
,沒有至少2.3G(12 + 113088217 *(12 + 2 * 4)字節)的內存,JVM將無法分配所需的空間。請注意,我沒有添加所需的填充空間(內存對齊)。
回答爲什麼lookup = new int[2*113088217];
表現更快。這是因爲處理的內存少得多,因爲我們沒有子數組(頭+元素+每個子數組的對齊),所以只需要(2 * 113088217 * 4 + 12)字節=〜804M。
如果您不想初始化太長的數組,您可以確定數組大小的限制,這不會讓您等待太久。我建議將一個長陣列分成更小的陣列。 定義一個保存陣列的列表。如果您的數組已填充,請將其添加到您的列表中。然後繼續填寫一個新的。
import java.util.ArrayList;
import java.util.List;
public class Tester {
private static final int LIMIT = 30;
private static int index = 0;
private static int[][] lookup;
private static List<int[][]> list = new ArrayList<int[][]>();
public static void main(String[] args) {
lookup = new int[LIMIT][1];
for (int i = 0; i <= 93; i++) {
addToArr(i);
}
list.add(lookup);
for (int[][] intArr : list) {
for (int i = 0; i < intArr.length; i++) {
System.out.print(intArr[i][0] + ",");
}
}
}
public static void addToArr(int value) {
if (index == LIMIT) {
list.add(lookup);
lookup = new int[LIMIT][1];
index = 0;
}
lookup [index++][0] = value;
}
}
打印:
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 ,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42 ,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67 ,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92 ,93,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,
** 警告 ** 不安全替代品 **
這不是一個確切的解決方案,但它可能是一個可行的選擇。這種方法有一些風險。但是如果真的有必要的話,你可以走這條路。此方法使用未記錄的sun.misc.Unsafe
類來分配堆外內存以存儲雙精度值。堆外意味着它不是垃圾收集,所以你需要注意釋放相關的內存。
以下代碼基於此blog post about sun.misc.Unsafe。
import java.lang.reflect.Field;
import sun.misc.Unsafe;
@SuppressWarnings("restriction")
public class SuperDoubleArray {
private final static Unsafe unsafe = getUnsafe();
private final static int INDEX_SCALE = 8;
private long size;
private long address;
public SuperDoubleArray(long size) {
this.size = size;
address = unsafe.allocateMemory(size * INDEX_SCALE);
}
private static Unsafe getUnsafe() {
try {
Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
singleoneInstanceField.setAccessible(true);
return (Unsafe) singleoneInstanceField.get(null);
} catch (IllegalArgumentException | SecurityException
| NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public void set(long i, double value) {
unsafe.putDouble(address + i * INDEX_SCALE, value);
}
public double get(long idx) {
return unsafe.getDouble(address + idx * INDEX_SCALE);
}
public long size() {
return size;
}
public void deallocate() {
unsafe.freeMemory(address);
}
}
以下代碼將打印來自單位化內存的一些隨機double值。
SuperDoubleArray sda = new SuperDoubleArray(100);
for (int i=0; i<sda.size(); i++) {
System.out.println(sda.get(i));
}
sda.deallocate();
有沒有安全/範圍的檢查,什麼都沒有,你可以很容易崩潰的JVM有了它,可能無法與非Sun的JRE工作,甚至可能會停止在未來SUN JRE版本的工作,但它可能在某些情況下是唯一的解決方案。它也可以分配>Integer.MAX_VALUE
大小的僞陣列,與Java數組不同。
java.nio.ByteBuffer.allocateDirect(...)
實際上在後臺使用相同的不安全類來分配字節的緩衝區,你可以使用ByteBuffer.allocateDirect(8*size).asDoubleBuffer()
它適應DoubleBuffer
,但ByteBuffer.allocateDirect(...)
仍在初始化用零緩衝,所以它可能有一個性能開銷。
據我瞭解的問題,真正的問題是與分配一個巨大的維數組,作爲在評論中提到
「靜態INT [] []查找=新INT [113088217] [2] ;不工作,雖然私人最終靜態int [] []查找=新詮釋[11308821] [2];(10倍以內)進入不到一秒鐘「
假設這是正確的,是的,數字它是骨頭緩慢。你是而不是分配一個113088217 * 2 整數單塊!您正在分配113088217個人陣列,它們是對象,它們中的每一個都必須分配在堆上:這意味着超過1億次JVM正在尋找空間,將其標記爲已用,可能在內存獲取時運行GC緊,等等......這些陣列每個都需要大量(在這些巨大的數字中)額外的內存,再加上每個都包含2個整數。
對於這個龐大的情況下:
1)切換指標,去
static int[][] lookup = new int[2][113088217]
不是分配1.13億陣列,該分配。在數組中查找時,切換兩個索引。
2)使一維數組,做自己查找
static int[] lookup = new int[2*113088217];
這需要做簡單的數學來找到合適的索引。不是直接訪問數組,而是編寫一個函數來完成數學計算,調用代碼應該使用該數學函數。
- 1. 如何避免「任務大小過大」?
- 2. 如何在Matlab中加速/避免乘法大矩陣?
- 3. 如何避免循環稀疏矩陣?
- 4. 如何避免@SuppressWarnings上通用陣列
- 5. 如何避免
- 6. 如何避免
- 7. 如何避免
- 8. 如何避免
- 9. 如何避免
- 10. 如何避免Yii大寫標籤?
- 11. 如何避免大in子句?
- 12. 如何避免對大熊貓據幀
- 13. 如何避免回顯大片的javascript
- 14. 如何避免最大連接限制?
- 15. 如何避免更改BLOB大小?
- 16. 避免覆蓋在陣列
- 17. 避免陣列複製
- 18. 如何避免android.os.NetworkOnMainThreadException
- 19. 如何避免typedef?
- 20. 如何避免ArrayIndexOutOfBoundsException?
- 21. 如何避免data.table
- 22. 如何避免SynchronizationLockException?
- 23. 如何避免sympy
- 24. 如何避免Express.js
- 25. 如何避免bad_alloc?
- 26. 如何避免NSCachedImageRep
- 27. 如何避免downcast?
- 28. 如何避免Angular.js
- 29. 如何避免Pycharm
- 30. 如何避免MissingMethodException?
將Java標記添加到您的問題 – 2016-01-01 18:19:41
設置vm參數Xms4000m有幫助。它現在在一分鐘內初始化。 – 2016-01-01 18:27:50
我無法編輯它,這不是我的問題。 – 2016-01-01 18:28:20