【发布时间】:2018-12-10 22:44:26
【问题描述】:
对于一项作业,我们被要求使用单链表实现数据结构。
我的问题是,在添加项目然后删除它们之后,java 程序仍然使用与以前相同的内存。
这是一个简单的例子
Deque<Integer> deck = new Deque<>();
for( int i =0; i < 500000;i++) {
deck.addFirst(i);
}
for( int i =0; i < 500000;i++) {
deck.removeFirst();
}
System.out.println("end"); //Debugger here
添加 50 万个项目会消耗 27mb 的内存。 删除它们后仍为 27mb。 最后用调试器跳转,变量deck有字段first = null 和计数 = 0;
为什么会这样?甲板是空的,没有项目,但内存仍然像以前一样使用。
代码通过了所有的正确性测试,但在内存测试中失败了。
我还查看了逐步调试器,并且正在做应该做的事情。
可能是在 removeFirst() 我没有将任何内容设置为 null 而只是将 first 分配为 first.next 吗?
编辑:这是内存测试的输出
Test 10: Total memory usage after inserting 4096 items, then successively
deleting items, seeking values of n where memory usage is maximized
as a function of n
n bytes
---------------------------------------------------
=> passed 3200 65592
=> passed 1600 65592
=> FAILED 800 65592 (1.7x)
=> FAILED 400 65592 (3.4x)
=> FAILED 200 65592 (6.7x)
=> FAILED 100 65592 (13.1x)
=> FAILED 50 65592 (25.3x)
==> 2/7 tests passed
如您所见,有 50 个元素仍在使用 65592
编辑2:
// remove and return the item from the front
public Item removeFirst() {
if (this.isEmpty()) throw new java.util.NoSuchElementException();
Item current = first.Item;
first = first.Next;
count--;
return current;
}
这是 removeFirst()
编辑3:
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
/**
* Created by Alex on 6/30/2018.
*/
public class Deque<Item> implements Iterable<Item> {
private Node first;
private int count;
private class Node {
private Node Next;
private Item Item;
}
// construct an empty deque
public Deque() {
first = null;
count = 0;
}
// is the deque empty?
public boolean isEmpty() {
if (count == 0) {
return true;
}
return false;
}
// return the number of items on the deque
public int size() {
return count;
}
// add the item to the front
public void addFirst(Item item) {
if (item == null) throw new IllegalArgumentException();
Node temp = new Node();
temp.Item = item;
temp.Next = first;
first = temp;
count++;
}
// add the item to the end
public void addLast(Item item) {
if (item == null) throw new IllegalArgumentException();
if (isEmpty()) {
addFirst(item);
} else {
Node last = first;
while (last.Next != null) {
last = last.Next;
}
Node newLast = new Node();
newLast.Item = item;
newLast.Next = null;
last.Next = newLast;
count++;
}
}
// remove and return the item from the front
public Item removeFirst() {
if (this.isEmpty()) throw new java.util.NoSuchElementException();
Item current = first.Item;
first = first.Next;
count--;
return current;
}
// remove and return the item from the end
public Item removeLast() {
if (isEmpty()) throw new java.util.NoSuchElementException();
if (size() == 1) {
return removeFirst();
}else {
Node newLast = first;
Node oldLast = first;
while (oldLast.Next != null) {
newLast = oldLast;
oldLast = oldLast.Next;
}
newLast.Next = null;
count--;
// Item lastItem = ;
return oldLast.Item;
}
}
// return an iterator over items in order from front to end
public Iterator<Item> iterator() {
return new DequeIterator();
}
private void debug() {
Iterator<Item> deckIter = iterator();
while(deckIter.hasNext()) {
System.out.println(deckIter.next());
}
System.out.println(isEmpty());
System.out.println("Size:" + size());
}
// an iterator, doesn't implement remove() since it's optional
private class DequeIterator implements Iterator<Item> {
private Node current = first;
public boolean hasNext() { return current != null; }
public void remove() { throw new UnsupportedOperationException(); }
public Item next() {
if (!hasNext()) throw new NoSuchElementException();
Item item = current.Item;
current = current.Next;
return item;
}
}
// unit testing (optional)
public static void main(String[] args) throws InterruptedException {
Deque<Integer> deck = new Deque<>();
for( int i =0; i < 500000;i++) {
deck.addFirst(i);
}
for( int i =0; i < 500000;i++) {
deck.removeFirst();
}
System.out.println("end");
TimeUnit.MINUTES.sleep(5);
}
}
Edit4:这些是内存限制
谢谢。
【问题讨论】:
-
Java 会在需要的时候获取内存;不早于。您如何确定使用了多少内存?另外,“正确性测试”是如何定义的?
-
我正在查看 Windows 上的任务管理器。编辑:正确性测试只是测试程序的输出,我将添加内存测试的输出
-
您能展示一下您的
removeFirst()实现吗?我也想知道那个测试用例是怎么实现的。 -
@FoxAlex Java 在程序结束之前可能不会向操作系统释放内存。不过,该内存将可用于
new运算符的未来分配。这是一个性能特征。 Java 可以(或应该能够)比操作系统更快地为new请求获取内存。 -
见stackoverflow.com/questions/1582209/… 和stackoverflow.com/questions/30458195/…。 (可能是重复的?我认为我们不能比那些问答封面更多地推测这一点。)
标签: java memory data-structures singly-linked-list