我正在开发与私有以太坊区块链网络交互的REST服务。首先,我将Java与Web3j库和Jersey一起使用。一切正常,但服务的一个实例(不是geth客户端)占用了500MB的内存!由于我需要同时运行多个实例(约40个)以进行仿真,我想要些轻的东西。
因此,我切换到Go(32位版本,Windows 10)和原始的go-ethereum软件包。但是,我很惊讶地发现,在我调用并存储bind.NewTransactor()
的结果后,程序的内存消耗上升到约250MB ,该结果返回一个{{1 }}。我查看了来源,但无法解释这种行为。
那很正常吗(如果是,为什么?)还是我错过了什么?
这是我的代码:
*TransactOpts
答案 0 :(得分:0)
好的,我没有真正找到问题的答案,但是当我找到解决方法时,我还是会分享它。
按照@MichaelHampton的建议,我对程序进行了概要分析。 top 10
命令显示了以下内容:
(pprof) top 10
Showing nodes accounting for 256MB, 99.88% of 256.30MB total
Dropped 15 nodes (cum <= 1.28MB)
flat flat% sum% cum cum%
256MB 99.88% 99.88% 256MB 99.88% github.com/ethereum/go-ethereum/vendor/golang.org/x/crypto/scrypt.Key
0 0% 99.88% 256MB 99.88% github.com/ethereum/go-ethereum/accounts/abi/bind.NewTransactor
0 0% 99.88% 256MB 99.88% github.com/ethereum/go-ethereum/accounts/keystore.DecryptKey
0 0% 99.88% 256MB 99.88% github.com/ethereum/go-ethereum/accounts/keystore.decryptKeyV3
0 0% 99.88% 256MB 99.88% github.com/ethereum/go-ethereum/accounts/keystore.getKDFKey
0 0% 99.88% 256.01MB 99.88% main.main
0 0% 99.88% 256.30MB 100% runtime.main
如您所见,内存消耗来自软件包Key
中的scrypt
函数,该函数由bind.NewTransactor(...)
间接调用。从文档中:
密钥从密码,salt和cost参数派生密钥,并返回一个长度为keyLen的字节片,可用作加密密钥。
尤其是,这对应于如何从JSON钱包文件生成私钥。实际上,该函数本身为密码计算分配了很多内存。不过,我不明白的是为什么这么大的内存分配似乎在密钥生成后仍然存在(当我紧接着用log.Fatal(http.ListenAndServe(":8080", nil))
启动服务器时观察到了持久性)。
为证实我的怀疑,我使用了另一种方式来生成我的*TransactOpts
,该方式包括直接从密钥的十六进制表示形式获取密钥,而不是从钱包文件中生成密钥:
func main() {
privateKey, err := crypto.HexToECDSA("myKeyInHex")
if err != nil {
log.Fatal(err)
}
auth := bind.NewKeyedTransactor(privateKey)
_ = auth
}
尽管bind.NewTransactor
和bind.NewKeyedTransactor
返回的对象完全相同(唯一的区别在于密钥的生成方式),但使用bind.NewTransactor
则可产生256MB的持久存储力内存分配,而不是bind.NewKeyedTransactor
的几个KB,如下所示:
(pprof) top 10
Showing nodes accounting for 11.04kB, 100% of 11.04kB total
Showing top 10 nodes out of 19
flat flat% sum% cum cum%
6.83kB 61.90% 61.90% 6.83kB 61.90% time.initLocalFromTZI
4.21kB 38.10% 100% 4.21kB 38.10% github.com/ethereum/go-ethereum/crypto/sha3.(*state).clone (inline)
0 0% 100% 4.21kB 38.10% github.com/ethereum/go-ethereum/accounts/abi/bind.NewKeyedTransactor
0 0% 100% 4.21kB 38.10% github.com/ethereum/go-ethereum/crypto.Keccak256
0 0% 100% 4.21kB 38.10% github.com/ethereum/go-ethereum/crypto.PubkeyToAddress
0 0% 100% 4.21kB 38.10% github.com/ethereum/go-ethereum/crypto/sha3.(*state).Sum
0 0% 100% 6.83kB 61.90% github.com/pkg/profile.Start
0 0% 100% 6.83kB 61.90% github.com/pkg/profile.Start.func2
0 0% 100% 6.83kB 61.90% log.(*Logger).Output
0 0% 100% 6.83kB 61.90% log.(*Logger).formatHeader
因此,为了进行模拟,我将从JSON钱包中生成私钥,并将其存储在上游的文本文件中,然后使用bind.NewKeyedTransactor(...)
。我知道这并不安全,但出于我的模拟目的就足够了。
但是,我很确定bind.NewTransactor
在内存消耗方面没有预期的行为,因此我将打开一个issue on the go-ethereum
repository。