瞬态内存中的 Java Card 对象实例
Posted
技术标签:
【中文标题】瞬态内存中的 Java Card 对象实例【英文标题】:Java Card Object Instance in Transient Memory 【发布时间】:2018-12-05 18:52:28 【问题描述】:我正在开发一个 Java Card 小程序(用于 Java Card 2.2.1),它需要一些临时对象来处理 APDU 命令。我对正确的内存管理有疑问。 我花了很多时间研究这些问题,但没有在某些 Java 卡 API 上找到任何澄清或良好的示例代码。我有两个主要问题:
如何创建瞬态对象数组(我的意思是 RAM 中的自定义对象,而不是 EEPROM 中的自定义对象)。我已经阅读了makeTransientObjectArray
,但它只返回 Object 类型的数组。例如,我知道如何使用makeTransientByteArray
创建瞬态字节数组,但我的问题是关于对象实例的瞬态数组。或者可能是java语言中的任何方式将字节数组转换为没有序列化的实例?
我只在传入 APDU 命令的过程中需要这个临时对象数组,不需要保留为我分配的内存。分配临时内存的最佳位置在哪里(在install
、select
、process
、...函数内)?
为更多解释编辑:
正如我已经从文档中读到的,任何对象实例都存储在 EEPROM 中。假设我知道我的过程算法中需要的最大对象数(比如 100 个)。我在 install 方法中生成了 100 个 MyClass 实例。 MyClass 的每个实例都包含 3 个字段:field1 是一个短类型,field2 是一个字节,field3 是一个短类型。所有这 100 个实例都将通过输入 APDU 命令来填充。如果对于每个命令,我在 EEPROM 上填充对象,这不是一个好习惯,因为它们是临时数据。 EEPROM 也有一个最大的写入周期。一种方法可能是,对于每个实例,我使用makeTransientByteArray
和makeTransientShortArray
为每个对象分配5 个字节。但正如我从文档中读到的那样,它按集群分配内存(32 字节 - 不确定大小),这是无效的。那么在这种情况下我必须做什么?
我的意思是如何处理瞬态记忆。如果在 install 函数中分配临时内存,其他小程序将无法使用。如果小程序是卡上唯一的一个小程序,最好在install
函数中分配所有临时内存。我想知道一种适用于所有条件(单小程序设备或多小程序设备)的通用有效方法。我也不确定,如果在install
内分配的临时内存,只要将卡插入读卡器,就可以在进程函数内使用。
【问题讨论】:
【参考方案1】:不幸的是,您尝试做的事情在 Java Card 的经典规范中是不可能的。正如您自己已经注意到的,对象实例始终存储在 EEPROM 中。所以你必须解决这个问题。
Java 是一种相对高级的语言,其中对象总是存储在一块特定的内存中。现在他们已经将这种类型的内存更改为 Java Card 的持久内存。然而,这将需要对语言进行彻底的重新设计,以允许在一种或另一种类型的内存中构造对象。如今,JCF 当然可以考虑为此使用注释 - 这仍然非常棘手,但可能是可行的。
同样,对象不可能只通过一种处理方法存在,甚至数组类型也不可能。要实现这一点,您要么必须有一个附加堆,要么必须有一个实时垃圾收集器。管理一个堆和相互增长的堆栈已经够难的了,而实时 GC 也不是当前经典实现中存在的东西。我们在这里工作的环境极其受限。
所以基本上你必须绕过平台的限制。
一个好的策略是创建一个包含临时内存或引用现有内存的对象缓存例如 APDU 缓冲区中的内存。对象将在安装或个性化期间创建。然后可以在必要时检索这些对象,使用这些对象并将其返回到缓存中。为了给您一个想法,请查看 Java 的 ByteBuffer.wrap()
方法,该方法允许您对现有数组的一部分执行缓冲区操作。现在考虑该类型的可重用对象。
另一个合乎逻辑的解决方案是根本不使用 OO 编程。嘿,OO 一切都很好,但我们在这里讨论的是 RAM 为 8 到 10 KiB 的芯片最大。会有限制。可以用对象完成的事情通常也可以只用方法完成(实际上,您可以证明这种情况,因为没有对象的 Java 无疑是图灵完备的,但如果您坚持自己的设计,那就没有什么安慰了) .
关于你的文字的注释:
不,您不能将字节数组转换为对象实例。一般来说,这将符合 Java 和 OO 的所有原则。如果可能的话,包括数据封装在内的一切都会被破坏。您当然可以反序列化自己并将结果放入缓存之外的对象中(参见上面的策略)。 内存通常只应在安装或个性化期间分配,或者很可能在使用延迟实例化发布后分配一次。 您不需要 100 个活动对象。您只有几个对象需要在某个特定时间“活着”。利用这些信息! 内存分配特定于平台实现。肯定有一些“集群”规模较小的平台;平台通常会尝试对齐内存中的数据,因此这也取决于系统/芯片的设计。 使用CLEAR_ON_DESELECT
创建的内存可能可供其他小程序使用。如果它们被选中,那么这个 RAM 就不再需要了。一个聪明的实现会将该内存保持在堆的顶部(仍然很棘手,但是嘿)。正如所指出的,这在选择实例后变得可用。只有在选择了小程序之后才会调用 process 方法(即使是为了处理初始的 SELECT APDU 本身)。
【讨论】:
【参考方案2】:如何创建瞬态对象数组(我的意思是 RAM 中的自定义对象,而不是 EEPROM 中的自定义对象)。
JavaCard 规范提供了一个方法makeTransientObjectArray(short, byte)
来创建一个临时对象数组。这将在 RAM 上分配内存,然后您可以将对象的引用存储在此内存中。
Object[] aob = JCSystem.makeTransientObjectArray(lengthOfArray, CLEAR_ON_..event);
aob[0] = ((YourClass)new YourClass(param));
aob[1] = ((YourClass)new YourClass(param));
..
但是,您仍然无法完全实现您的目标,因为在 YourClass
中实例化的对象可能仍在消耗来自 非瞬态存储器 (EEPROM) 或 瞬态 ( RAM) 取决于它们在YourClass
的构造函数中的分配。只有YourClass
对象的引用才是您存储在瞬态空间(aob)中的内容。
我只在传入过程中需要这个瞬态对象数组 APDU 命令并且不需要保留为我分配的内存。在哪里 是分配此临时内存的最佳位置(在安装内部, 选择、处理、...函数)?
所有资源最好在install()
方法中分配。
【讨论】:
除上述之外,您应该只创建一次对象,因为此内存不是“垃圾收集”。你为什么不考虑创建一个对象实例并在内部分配瞬态数组等。这样你就可以在不影响内存的情况下实现同样的目标。 确实,但最初的问题与瞬态对象数组有关,而提供的 sn-p 只是一个与缺点相关的示例。 别误会我的意思。我只是在他的解决方案中指出了一个设计问题。 由于垃圾不是自动收集的,上面会导致持久内存泄漏(你肯定想避免在许多智能卡芯片上收集垃圾,这可能需要很长时间,因为它通常表示压缩所有持久数据)。以上是关于瞬态内存中的 Java Card 对象实例的主要内容,如果未能解决你的问题,请参考以下文章