在下面,您看到一个我编写的程序,该程序在调用requestObjectDeletion()
方法后可以查看不同字段的状态和内存分配:
public class ReqObjDel extends Applet {
static byte[] buffer = new byte[2];
static boolean isNull = false;
private ReqObjDel() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new ReqObjDel().register();
}
public void process(APDU arg0) throws ISOException {
if (selectingApplet()) {
return;
}
if (buffer != null && (short) buffer.length == (short) 10) {
return;
}
byte[] oldBuffer = buffer;
buffer = new byte[10];
JCSystem.requestObjectDeletion();
if (oldBuffer == null)
isNull = true;
if (isNull) {
ISOException.throwIt((short) 0x1111);
} else
ISOException.throwIt((short) 0x0000);
}
}
据我所知,此方法回收“不可达”对象正在使用的内存。为了“不可到达”,对象既不能由静态字段也不能由对象字段指向。因此,在上述程序中调用
requestObjectDeletion()
会回收oldBuffer
所引用的EEPROM部分(据我所知,oldBuffer
既不是类字段也不是对象字段,对吗?)。在这种情况下,我希望oldBuffer == null
以及JCRE必须返回0x1111
。但是输出意外地是0x0000
:OSC: opensc-tool -s 00a404000b0102030405060708090000 -s 00000000
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 00 00 00
Received (SW1=0x00, SW2=0x00)
Q1:我可以得出什么结论?
那部分内存没有回收?
内存的那部分被回收了,但是
oldBuffer
仍然是对它的引用吗?还有什么吗
Q2:在调用此方法之前和之后,是否有任何方法可以获取可用内存大小? (即是否有任何方法返回可用内存的大小[未分配]?)
更新1:尝试
JCSystem.getAvailableMemory()
基于@vojta答案,我更改了程序,使行
byte[] oldBuffer = buffer;
仅运行一次(使用名为isFirstInvocation
的标志),并在两次连续的process()
方法调用中返回可用内存:public class ReqObjDel extends Applet {
static byte[] buffer = new byte[10];
static boolean isFirstInvocation = true;
private ReqObjDel() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new ReqObjDel().register();
}
public void process(APDU arg0) throws ISOException {
if (selectingApplet()) {
return;
}
short availableMem1 = JCSystem
.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
if (isFirstInvocation) {
byte[] oldBuffer = buffer;
buffer = new byte[10];
JCSystem.requestObjectDeletion();
firstInvocation = false;
}
short availableMem2 = JCSystem
.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
short availableMemory = (short) (availableMem1 + availableMem2);
ISOException.throwIt(availableMemory);
}
}
这是输出:
OSC: osc -s 00a404000b0102030405060708090000 -s 00000000 -s 00000000
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 00 00 00
Received (SW1=0xFF, SW2=0xFE)
Sending: 00 00 00 00
Received (SW1=0xFF, SW2=0xFE)
由于两个调用都返回相等的值,因此我认为JCRE在调用
requestObjectDeletion()
之后立即回收该部分内存,对吗? 最佳答案
首先,根据我的个人经验制定一条规则:如果可能,请不要使用垃圾收集器。 GC非常慢,甚至可能很危险(请参阅Javacard - power loss during garbage collection)。
Q1:
如果确实需要使用GC,请阅读文档:
小程序调用此方法以触发对象删除
Java Card运行时环境的服务。如果Java Card运行时
环境实现对象删除机制,请求是
仅在此时登录。 Java Card运行时环境必须
在下一次调用之前安排对象删除服务
Applet.process()方法。
简而言之,JCSystem.requestObjectDeletion();
没有立即生效。这就是为什么您的局部变量oldBuffer
保持不变的原因。
Q2:要找出您的小程序有多少持久性内存,请使用:
JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT)
对更新1的回答:
JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT)
对于具有32767字节以上持久性存储的卡可能会造成混淆。此类卡通常提供自己的专有方式来查找可用内存。如果可用字节数大于32767,则此
方法返回32767。