如何避免大阵
回答
简短回答:不。数组创建时总是被清零。
如果您的配置文件显示这是一个主要瓶颈,您可以考虑保留一个数组实例池,每个配置文件的长度要大于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. 如何避免@SuppressWarnings上通用阵列
- 4. 如何避免
- 5. 如何避免更改BLOB大小?
- 6. 如何避免对大熊猫据帧
- 7. 如何避免最大连接限制?
- 8. 如何避免大in子句?
- 9. 避免覆盖在阵列
- 10. 避免阵列复制
- 11. 如何避免NoRouteToHostException?
- 12. 如何避免MSDTC?
- 13. 如何避免DatabaseObjectNotClosedException?
- 14. 如何避免SynchronizationLockException?
- 15. 如何避免刮
- 16. 如何避免OutOfMemoryError
- 17. 如何避免与
- 18. 如何避免java.util.NoSuchElementException
- 19. 如何避免include_once
- 20. 如何避免“RewriteBase”
- 21. 如何避免MissingMethodException?
- 22. 如何避免Angular.js
- 23. 如何避免DatabaseObjectNotClosedException
- 24. 如何避免NSCachedImageRep
- 25. 如何避免Express.js
- 26. 如何避免此
- 27. 如何避免texbox
- 28. 如何避免NullReferenceException
- 29. 如何避免UnauthorizedAccessException?
- 30. 如何避免AVPlayer
将Java标记添加到您的问题 – 2016-01-01 18:19:41
设置vm参数Xms4000m有帮助。它现在在一分钟内初始化。 – 2016-01-01 18:27:50
我无法编辑它,这不是我的问题。 – 2016-01-01 18:28:20