我在C ++和Java中为md5实现了一个强制执行器,并且对它们的效率有何不同有疑问。
数据和复杂度(E ^密码长度)与时间的关系图如下:http://i.imgur.com/hckCe8f.png
密码是简单的“b”重复填充长度
在C ++中我使用了md5的这个实现:zedwood.com/article/cpp-md5-function
在Java中,我使用了此站点上的第二个实现:http://www.asjava.com/core-java/java-md5-example/
在递归C ++实现中,我的循环代码是在一个单独的类中完成的:
class bruteChar {
string charset;
char last_char;
string str;
string double_start;
char reverse_charset[256];
private:
string next(string s)
{
size_t length = s.size()-1;
if(length == 0)
{
if( s[0]==last_char)
return double_start;
return string(1, charset[reverse_charset[s[length]]+1]);
}
if(s[length] == last_char)
return next(s.substr(0,length))+charset[0];
else
return str.substr(0,length)+string(1, charset[reverse_charset[s[length]]+1]);
};
public:
void start (string chars)
{
charset = chars;
str=charset[0];
last_char=charset[charset.size()-1];
double_start=charset[0];
double_start+=charset[0];
for(size_t i = 0; i < charset.size(); ++i)
reverse_charset[charset[i]]=i;
reverse_charset[charset[charset.size()]]=0;
}
string next()
{
str=next(str);
return str;
}
};
在Java中我使用了自定义类
public class picochar {
public static char[] charset = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
int num;
int mod;
picochar(int init, int mod)
{
num = init%mod;
}
picochar(char init, int mod)
{
for(int i = 0; i < mod; i++)
{
if(charset[i] == init)
num = i;
}
}
public char get()
{
return charset[num];
}
public boolean equals(char ch)
{
return (get() == ch);
}
public void increment()
{
num++;
}
}
以及以下方法
public static String next(String s) {
int length = s.length();
picochar pc = new picochar(s.charAt(length - 1),mod);
if(pc.equals(picochar.charset[mod-1]))
return length > 1 ? next(s.substring(0, length - 1)) + 'a' : "aa";
pc.increment();
return s.substring(0, length - 1) + pc.get();
}
为什么Java在计算哈希值时比C ++更有效率?
我是否只是使用Java的高效MD5实现和C ++的实用程序?
我认为C ++会比Java快得多,因为Java必须通过JVM运行所有内容而C本身就是这样做。
然而,Java远远超过了C ++解决方案。如果这仅仅是因为我对C ++程序的编码不好,我该如何解决?
编辑删除不同的C ++程序,现在两个解决方案都递归循环。
我确定了在没有散列的情况下循环所需的时间,这里Java的速度是C的两倍,这是由@Dunes解释的。当重新编码为不递归地使用substr()而是改变原始字符串时,C的速度大约是Java的两倍。
我做了一些测试,将哈希“hello”1&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 25到C实现。
在经过几秒钟的哈希处理后,C ++会有类似的性能提升,但增益远远不及Java的增益。
那么为什么Java会更好地预热呢?
答案 0 :(得分:1)
看起来c ++实现速度太慢的原因是因为你按值传递字符串。这是每次使用字符串参数调用方法或返回字符串时,程序必须为整个字符串创建一个全新的副本。
然而,因为Java具有不可变的字符串,所以它可以通过传递相同字符串的不同视图而逃脱。 String.substring
不复制支持字符数组。相反,新的字符串对象只跟踪与支持字符数组相关的起始索引和长度。当不明智地使用子字符串时,它可能导致内存泄漏 - 只要存在,一个char视图将保持原始的百万字符后备阵列存活。
答案 1 :(得分:0)
原来我使用的是低效的md5实现 这是计算2 27 哈希所花费的时间与openssl哈希时间的比较
openssl v1
17.4911
openssl v2
14.9546
custom
291.201