【发布时间】:2016-08-08 20:13:42
【问题描述】:
所以我最近尝试使用 Java 中的单个链表实现 Stack,但我遇到了这个问题。如果我将 100000 个元素自然地推入堆栈,则内存会增加,因为堆栈需要 100000 个节点来存储对象。但是,当堆栈清空时(在 100,000 次弹出后),对这些节点及其内容的引用应超出范围,因此如果堆栈填满,内存使用量不应增长。但是,当我的代码中发生这种情况时,内存会翻倍。换句话说,pop 似乎没有充分删除引用或允许垃圾收集,我希望有人能告诉我原因。
这里是栈类
public class Stack<T> {
private Node<T> top;
private int size;
private long limit;
public boolean isEmpty() {
return this.size == 0;
}
public void setStackLimit(long limit) {
this.limit = limit;
}
public int size() {
return size;
}
public Stack() {
this(1000L);
}
public Stack(long limit) {
this.size = 0;
this.top = null;
this.limit = limit;
}
public void push(T o) throws StackOverflowException{
if (this.size == this.limit) throw new StackOverflowException("The stack overflowed");
if (this.top == null) this.top = new Node<T>(o);
else {
Node<T> r = new Node<T>(o);
Node<T> temp = this.top;
this.top = r;
this.top.setNext(temp);
}
this.size++;
}
@SafeVarargs
public final void mpush(T... o) throws StackOverflowException{
for (T ob: o) {
this.push(ob);
}
}
public T pop() throws EmptyStackException{
if (this.top == null) throw new EmptyStackException("The stack is empty");
else {
T o = this.top.getPayload();
this.top = this.top.getNext();
this.size--;
return o;
}
}
public boolean empty() {
while (!this.isEmpty()){
try {
this.pop();
}
catch (Exception e) {
return false;
}
}
return true;
}
public String printStack() {
String stack = "";
Node<T> temp = this.top;
while (temp != null){
if (temp.getPayload() instanceof Stack<?>) {
Stack<?> stack2 = (Stack<?>)temp.getPayload();;
stack = "| " + stack2.printStack() + stack;
} else
stack = "|" + temp.getPayload().toString() + stack;
temp = temp.getNext();
}
return stack.replaceAll("[| ]$","");
}
public T peek() throws EmptyStackException {
if (this.top == null) throw new EmptyStackException("The stack is empty");
else {
T o = this.top.getPayload();
return o;
}
}
public boolean isFull() {
return this.size == this.limit;
}
public Object[] toArray() {
Object[] returnvalue = new Object[this.size];
int index = this.size-1;
Node<T> temp = this.top;
while (index >= 0) {
returnvalue[index--] = temp.getPayload();
temp = temp.getNext();
}
return returnvalue;
}
public String toString() {
try {
return "<Stack object of size " + this.size() + " last element: " + this.peek().toString() + ">";
} catch (Exception e) {
return "<Empty stack object of size " + this.size() + ">";
}
}
}
这是Node的实现
public class Node<T> {
private T payload;
private Node<T> next;
public Node(T payload) {
this.payload = payload;
}
public Node<T> getNext(){
return this.next;
}
public boolean hasNext() {
return this.next != null;
}
public T getPayload() {
return this.payload;
}
public void setNext(Node<T> n) {
this.next = n;
}
public void setPayload(T o) {
this.payload = o;
}
}
【问题讨论】:
-
这不是内存泄漏。请了解内存泄漏是什么意思。这只是因为 jvm 在进程中保存了你的内存。这并不意味着你的记忆丢失了。
-
另外,在 gc 的预期中。没有任何 gc 实现在创建垃圾后立即收集垃圾的规则。
-
我知道当引用被删除时,内存不会从java进程中释放,但不应该继续消耗内存。如果它不将 RAM 还给操作系统,那么它至少在重新填充后不会获得更多内存。
-
假设您的引用丢失,jvm 可能会或可能不会决定 gc 您的垃圾,因此看到您的内存使用量增加是合理的。 100k 不是触发 gc 的尺度。
-
100,000 个小对象并没有那么多内存,可能只有几兆字节。 GC 不运行是完全合理的。如果您只是想看看会发生什么,您可以尝试致电
System.gc();。 (普通代码不应该调用System.gc();。通常你应该让GC 做它的事情而不用担心它。)在Java 中造成任何类似于泄漏的事情是非常困难的。 (examples)
标签: java memory memory-leaks stack