Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为堆栈上的对象而不是堆上的对象预分配内存_Java_Memory_New Operator - Fatal编程技术网

Java 为堆栈上的对象而不是堆上的对象预分配内存

Java 为堆栈上的对象而不是堆上的对象预分配内存,java,memory,new-operator,Java,Memory,New Operator,以c中的LinkedList为例,我在堆栈上显式地预先分配了N个节点结构,用作节点池或节点堆栈,而不是使用慢速mallocs和frees,我不需要在运行中释放节点的功能,因此堆栈可以: #define N 40000 typedef struct node_t { void * ele; struct node_t * next; }node,*Pnode; node Stack[N];//memory allocation for the linkedlist nodes

以c中的LinkedList为例,我在堆栈上显式地预先分配了N个节点结构,用作节点池或节点堆栈,而不是使用慢速mallocs和frees,我不需要在运行中释放节点的功能,因此堆栈可以:

#define N 40000

typedef struct node_t {
    void * ele;
    struct node_t * next;
}node,*Pnode;

node Stack[N];//memory allocation for the linkedlist nodes
int sp=0;

Pnode createNode(void * x) {
    Pnode temp=&Stack[sp++];
    temp->ele=x;
    temp->next=NULL;
    return temp;
}
当我试图把上面的想法移植到JAVA中时,我想到了这个。。。您能否完成该类以使Node[]堆栈成为一个nodes对象数组,该对象的内存在堆栈中预先分配

public class Node<E>  {

    private final static int n = 40000;
    private static Node[] stack = ?
    private static int sp = 0;

    private E ele;
    private Node next;

    private Node () {}
    public Node createNode(E e) {
        stack[sp].ele=e;
        stack[sp].next=null;
        return stack[sp++];
    }
}

基本上,我想知道这一点,因为我知道我希望我的程序能够做什么,我知道我不需要释放和重用内存块的能力,我希望能够快速分配节点对象,即使我的程序几乎出现堆溢出。最大容量为N的节点堆栈和像我这样运行的索引非常适合我…

否。Java没有在堆栈上分配内存的显式机制

使用new是分配内存的唯一方法。然后由JVM决定内存的来源,并从那时起对其进行管理

编辑:我刚刚仔细看过你的代码。您甚至没有在堆栈上分配内存。您所做的似乎是拥有一个位于数据段上的堆栈数据结构,并且您可以自己管理它

在Java中,没有直接的等价物:

node Stack[N];
换句话说,无法在一个连续的内存块中构造N个对象。您必须分配一个包含N个引用的数组,然后创建N个对象

话虽如此,但请记住,在现代JVM中,new本质上相当于指针碰撞。这是:便宜;b与您对sp的操作类似

您能否完成该类以使Node[]成为堆栈中的节点数组对象

不需要。Java根据自己的启发式为您管理内存分配。据我所知,JLS中没有任何东西可以保证特定对象将被分配到何处

我的问题是-为什么要在堆栈上分配它?根据垃圾收集器的内部状态,您认为您比Hotspot更了解此数据的最佳位置吗?基于我公认的非专家知识,无论如何,这些对象最好放在堆上的伊甸园池中


使用Java需要学习的一件事就是放手,相信VM关于在何处分配内存的决定。只要您避免编写复杂的算法,它通常会在这些决策方面做得非常好,通常比开发人员做得更好,因为它在编写代码时会考虑运行时可用的信息,而不是被迫采用静态二分法。

您似乎想要的是一个对象池

一个简单的池就是使用ArrayList

public class Node<E>  {

    private final static int MAX_SIZE = 40000;
    private final static List<Node> freeNodes = new ArrayList<>();

    private E ele;
    private Node next;

    private Node () {}

    public static Node<E> acquireNode(E e) {
        Node node = freeNodes.size() > 0 
                    ? freeNodes.remove(freeNodes.size()-1) 
                    : new Node();
        node.ele = e;
        return node;
    }

    public static void freeNode(Node<E> node) {
        if(freeNodes.size() < MAX_SIZE) {
            node.next = null;
            freeNodes.add(node);
        }
    }
}

我建议使用不同的结构,例如ArrayList或RingBuffer,而不是使用绑定到创建大量对象的LinkedList,因为它们都不需要这些节点。做某事最快的方法就是根本不做

使用new是动态分配内存的唯一方法,但我并没有尝试动态分配内存,那么有可能吗?@OfekRon:正如我所说,没有机制强制JVM在堆栈上分配内存。@您的编辑,有什么不同?据我所知,如果我错了,所有变量都会纠正我,因为你在程序中声明的是在堆栈上分配内存。由compiler@OfekRon:在我看来,您过早地进行了优化。编写代码,分析结果,如果速度太慢,请用精确的基准测试呈现您的特定代码。然后我们就可以给你具体的建议,如何使它更快。@OfekRon:正如我一直在解释的,C结果不会自动应用于Java。在我的电脑上,分配5000万个像你这样的对象并将它们存储在Java数组中需要大约10秒钟。无论如何,在我们看到一些实际的代码和基准测试之前,这个讨论不会真正深入。这是因为我知道我希望我的程序能够做什么,我知道我不需要释放和重用内存块的能力,我希望能够像Lighting一样快速分配节点对象,即使我的程序几乎出现堆溢出。。。当我分配越来越多的节点时,我的程序变慢了,当我使用malloc而不是仅仅预先分配节点时,上面的C代码也出现了同样的情况。您是否使用了探查器或-verbose:gc来确定慢度取决于分配给新对象的内存位置?一般来说,即使堆几乎满了,在没有碎片的情况下,分配所需的内存块也应该是一个固定的时间操作,这里就是这种情况。我尽量避免使用LinkedList,特别是在java中,但例如id宁愿合并20亿个按链接l排序的节点
列表中有一个40亿个节点排序的链表,然后数组也一样。你在那里做的不算,也不做我想做的,因为在数组列表中,没有任何内容,我必须用堆上的new分配的新节点填充arraylist,这不是我想要的。如果你有一个60亿个节点的链表,你将有大约144 GB的对象开销,仅仅是对象的节点+16字节头大约32字节。如果你有数十亿个对象/记录要合并,或者你不能在Java中一次创建多个对象,我建议使用堆外内存。数组是引用或基本体的数组,而不是对象。这是你能得到的最接近的。