- 论坛徽章:
- 27
|
1.Java中字符串分割的性能讨论
答:若是分隔的逻辑很简单并且数据量很大的话,我会采用stringbuffer+加charAt进行分割,分割后产生一个记录位置的数组,这样既减少占用内存又节省时间;
若是一般性的话使用split进行分隔
可以考虑使用java调用c程序进行分割
2. 如果程序性能不如人意,如何找到代码中的性能瓶颈
答:1)查找字符串比较次数比较多的地方,若是比较次数超过1000次,建议使用hashMap来替换- /**
- * switch的实现 map比较稳定,if最慢,switch在数量少于10个时最快,随着数量增加下降厉害,在switch最好把出现次数最多的判断放在最前面
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test5() {
- HashMap<String, Integer> types = new HashMap<String, Integer>() {
- {
- int i = 0;
- this.put("a", i++);
- this.put("b", i++);
- this.put("c", i++);
- this.put("d", i++);
- this.put("e", i++);
- }
- };
- String a = "e";
- int b = 0;
- long startTime;
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- if ("a".equals(a)) {
- b = 0;
- } else if ("b".equals(a)) {
- b = 1;
- } else if ("c".equals(a)) {
- b = 2;
- } else if ("d".equals(a)) {
- b = 3;
- } else if ("e".equals(a)) {
- b = 4;
- }
- }
- System.out.println(new Date().getTime() - startTime);
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- b = types.get(a);
- }
- System.out.println(new Date().getTime() - startTime);
- int c = 14;//改为0的话则最快
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- switch (c) {
- case 0:
- break;
- case 1:
- break;
- case 2:
- break;
- case 3:
- break;
- case 4:
- break;
- case 5:
- break;
- case 6:
- break;
- case 7:
- break;
- case 8:
- break;
- case 9:
- break;
- case 10:
- break;
- case 11:
- break;
- case 12:
- break;
- case 13:
- break;
- case 14:
- break;
- default:
- break;
- }
- }
- System.out.println(new Date().getTime() - startTime);
- }
复制代码 2)输入和输出(I/O),避免多次读写同一个文件,读时最好尽量一次读取完需要的数据,
写时,先把要写的内容全部放到变量里,一次写入文件
3)对于数据库或者网络通信最好重用连接,不要每次查询都连接一次,可以采用连接池
3. 如果系统频繁发生Out of Memory异常,该如何分析和解决问题
1)查看一下java虚拟机申请的内存是不是太少
2)检查代码中循环次数最多的地方,最好使用stringbuffer代替string对字符串进行操作
3) 检查数据库查询的地方是否释放结果集,可以把大量的插入操作改为一次次操作,减少占用内存
4) 不要把大量数据存放在静态变量里
4、您在Java程序开发和调优中用到的一些有用的技巧
下面的代码是我做的性能测试代码,大家可以参考一下,有什么不对的请指教
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import java.util.StringTokenizer;
- public class Test {
- public static void main(String argv[]) {
-
- /*
- * 避免在循环条件中使用复杂表达式
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- *
- */
- // test0();
- /*
- * 如果只是查找单个字符的话,用charAt()代替startsWith()
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test1();
- /*
- * 能够使用移位的乘除,最好用移位
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test2();
- /*
- * 只有一个字符的字符串拼接,用''代替""
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test3();
- /**
- * try catch最好不要放在循环里
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test4();
- /**
- * switch的实现 map比较稳定,if最慢,switch在数量少于10个时最快,随着数量增加下降厉害
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test5();
- /*
- * 对于常量字符串,用'String' 代替 'StringBuffer' ,节省空间,节省时间
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test6();
- /*
- * 用'StringTokenizer' 代替 'indexOf()' 和'substring()'
- * 字符串的分析在很多应用中都是常见的。使用indexOf
- * ()和substring()来分析字符串容易导致StringIndexOutOfBoundsException。
- * 而使用StringTokenizer类来分析字符串则会容易一些,效率也会低一些。
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test7();
- /*
- * 不要在循环体中实例化变量 在循环体中实例化临时变量将会增加内存消耗
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test8();
- /*
- * 确定 StringBuffer的容量
- * StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小
- * ,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建
- * StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test9();
- /*
- * 尽可能的使用栈变量
- *
- * 如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static?
- * local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // test10();
- /**
- * 复制数组最好用System.arraycopy 逐个复制,最慢;批量复制,最快
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
-
- // copyArray();
- /*
- * 复制ArrayList数组最好用addAll addAll,最快;clone,次之,逐个最慢
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- // copyArrayList();
- /*
- * 复制Map最好用逐个复制最快,putAll最简单
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- copyMap();
-
- }
- int localN = 0;
- static int staticN = 0;
- /*
- * 避免在循环条件中使用复杂表达式
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test0() {
- ArrayList<Integer> a = new ArrayList<Integer>();
- for (int i = 0; i < 10000000; i++) {
- a.add(i);
- }
- long startTime;
- // 循环条件中使用复杂表达式
- startTime = new Date().getTime();
- for (int i = 0; i < a.size(); i++) {
- int j = a.get(i);
- }
- System.out.println(new Date().getTime() - startTime);
- // 循环条件中不使用复杂表达式
- startTime = new Date().getTime();
- for (int i = 0, maxlen = a.size(); i < maxlen; i++) {
- int j = a.get(i);
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 如果只是查找单个字符的话,用charAt()代替startsWith()
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test1() {
- String s = "sdfsdfsdfsdfdssssssssssssssssssssssssssssdfffffffffffffffa";
- long startTime;
- // startsWith
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- if (s.startsWith("a")) {
- }
- }
- System.out.println(new Date().getTime() - startTime);
- // charAt
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- if (s.charAt(0) == 'a') {
- }
- }
- System.out.println(new Date().getTime() - startTime);
-
- // charAt
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- if ("ab".equals("abcdssdds".substring(0, 2))) {
- }
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 能够使用移位的乘除,最好用移位
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test2() {
- long startTime;
- int a;
- //
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- a = 333333333 / 8;
- }
- System.out.println(new Date().getTime() - startTime);
- // charAt
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- a = 333333333 >> 3;
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 只有一个字符的字符串拼接,用''代替""
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test3() {
- long startTime;
- startTime = new Date().getTime();
- String s = "123";
- for (int i = 0; i < 10000000; i++) {
- String a = s + "d";
- }
- System.out.println(new Date().getTime() - startTime);
- // charAt
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- String a = s + 'd';
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /**
- * try catch最好不要放在循环里
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test4() {
- long startTime;
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- try {
- int a = Integer.parseInt("1");
- } catch (Exception e) {
- }
- }
- System.out.println(new Date().getTime() - startTime);
- startTime = new Date().getTime();
- try {
- for (int i = 0; i < 10000000; i++) {
- int a = Integer.parseInt("1");
- }
- } catch (Exception e) {
- }
- System.out.println(new Date().getTime() - startTime);
- int a=1;
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- if("sdffffffffffffffffffffffffffffffff".contains("a")){
- a = 0;
- }else{
- a = 1;
- }
- }
- System.out.println(new Date().getTime() - startTime);
- startTime = new Date().getTime();
-
- if("sdffffffffffffffffffffffffffffffff".contains("a")){
- for (int i = 0; i < 10000000; i++) {
- a = 0;
- }
- }else{
- for (int i = 0; i < 10000000; i++) {
- a = 1;
- }
- }
- System.out.println(new Date().getTime() - startTime);
-
- }
- /**
- * switch的实现 map比较稳定,if最慢,switch在数量少于10个时最快,随着数量增加下降厉害,在switch最好把出现次数最多的判断放在最前面
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test5() {
- HashMap<String, Integer> types = new HashMap<String, Integer>() {
- {
- int i = 0;
- this.put("a", i++);
- this.put("b", i++);
- this.put("c", i++);
- this.put("d", i++);
- this.put("e", i++);
- }
- };
- String a = "e";
- int b = 0;
- long startTime;
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- if ("a".equals(a)) {
- b = 0;
- } else if ("b".equals(a)) {
- b = 1;
- } else if ("c".equals(a)) {
- b = 2;
- } else if ("d".equals(a)) {
- b = 3;
- } else if ("e".equals(a)) {
- b = 4;
- }
- }
- System.out.println(new Date().getTime() - startTime);
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- b = types.get(a);
- }
- System.out.println(new Date().getTime() - startTime);
- int c = 14;//改为0的话则最快
- startTime = new Date().getTime();
- for (int i = 0; i < 10000000; i++) {
- switch (c) {
- case 0:
- break;
- case 1:
- break;
- case 2:
- break;
- case 3:
- break;
- case 4:
- break;
- case 5:
- break;
- case 6:
- break;
- case 7:
- break;
- case 8:
- break;
- case 9:
- break;
- case 10:
- break;
- case 11:
- break;
- case 12:
- break;
- case 13:
- break;
- case 14:
- break;
- default:
- break;
- }
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 对于常量字符串,用'StringBuffer' 代替 'String' ,节省空间,节省一半时间
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test6() {
- StringBuffer s = new StringBuffer("Hello");
- int maxlen=1000000;
- long startTime;
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- String t =new String("Hello ") + "World!";
- }
- System.out.println(new Date().getTime() - startTime);
-
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- StringBuffer t =new StringBuffer("Hello ").append("World!");
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 用'StringTokenizer' 代替 'indexOf()' 和'substring()'
- * 字符串的分析在很多应用中都是常见的。使用indexOf
- * ()和substring()来分析字符串容易导致StringIndexOutOfBoundsException。
- * 而使用StringTokenizer类来分析字符串则会容易一些,效率也会低一些。
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test7() {
- String domain = "www.a.com.";
- long startTime;
- startTime = new Date().getTime();
- for (int i = 0; i < 100000; i++) {
- int index = 0;
- while ((index = domain.indexOf(".", index + 1)) != -1) {
- domain.substring(index + 1, domain.length());
- // System.out.println(domain.substring(index+1,
- // domain.length()));
- }
- }
- System.out.println(new Date().getTime() - startTime);
- startTime = new Date().getTime();
- for (int i = 0; i < 100000; i++) {
- StringTokenizer st = new StringTokenizer(domain, ".");
- while (st.hasMoreTokens()) {
- st.nextToken();
- // System.out.println(st.nextToken());
- }
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 不要在循环体中实例化变量 在循环体中实例化临时变量将会增加内存消耗
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test8() {
- ArrayList<Integer> a = new ArrayList<Integer>();
- int maxlen = 10000000;
- for (int i = 0; i < maxlen; i++) {
- a.add(i);
- }
- long startTime;
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- Object o = new Object();
- o = a.get(i);
- }
- System.out.println(new Date().getTime() - startTime);
- Object o = new Object();
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- o = a.get(i);
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 确定 StringBuffer的容量
- * StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存
- * ,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建
- * StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test9() {
- int maxlen = 1000000;
- long startTime;
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- StringBuffer buffer = new StringBuffer(); // violation
- buffer.append("hellosdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- }
- System.out.println(new Date().getTime() - startTime);
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- StringBuffer buffer = new StringBuffer(128); // violation
- buffer.append("hellosdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
- }
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 尽可能的使用栈变量 如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static?
- * local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- public static void test10() {
- int maxlen = 100000000;
- long startTime;
- int n = 0;
- Test test = new Test();
- // 局部变量
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- n = i;
- }
- System.out.println(new Date().getTime() - startTime);
- // 类变量
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- test.localN = i;
- }
- System.out.println(new Date().getTime() - startTime);
- // 静态变量
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- Test.staticN = i;
- }
- System.out.println(new Date().getTime() - startTime);
- }
- //
- // /*1.尽量使用final修饰符。
- //带有final修饰符的类是不可派生的。在JAVA核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。
- // */
- // public static void test11() {
- // int maxlen = 10000000;
- // long startTime;
- // int n = 0;
- //
- // // 普通类
- // startTime = new Date().getTime();
- // A a = new A();
- // for (int i = 0; i < maxlen; i++) {
- // a.inc();
- // }
- // System.out.println(new Date().getTime() - startTime);
- //
- // // final类
- // startTime = new Date().getTime();
- // FinalA finalA = new FinalA();
- // for (int i = 0; i < maxlen; i++) {
- // finalA.inc();
- // }
- // System.out.println(new Date().getTime() - startTime);
- // }
- /**
- * 复制数组最好用System.arraycopy 逐个复制,最慢;批量复制,最快
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- static void copyArray() {
- int[] array1 = new int[10000000];
- int[] array2 = new int[10000000];
- for (int i = 0, maxlen = array1.length; i < maxlen; i++) {
- array1[i] = i;
- }
- long startTime;
- // 逐个复制,最慢
- startTime = new Date().getTime();
- for (int i = 0, maxlen = array2.length; i < maxlen; i++) {
- array2[i] = array1[i]; // Violation
- }
- System.out.println(new Date().getTime() - startTime);
- // 批量复制,最快
- startTime = new Date().getTime();
- System.arraycopy(array1, 0, array2, 0, 10000);
- System.out.println(new Date().getTime() - startTime);
- }
- /*
- * 复制ArrayList数组最好用addAll addAll,最快;clone,次之,逐个最慢
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- static void copyArrayList() {
- int maxlen = 1000000;
- ArrayList<Integer> array1 = new ArrayList<Integer>();
- ArrayList<Integer> array2 = new ArrayList<Integer>();
- ArrayList<Integer> array3 = new ArrayList<Integer>();
- ArrayList<Integer> array4;
- for (int i = 0; i < maxlen; i++) {
- array1.add(i);
- }
- long startTime;
- // 逐个复制,最慢
- startTime = new Date().getTime();
- for (int i = 0; i < maxlen; i++) {
- array2.add(array1.get(i)); // Violation
- }
- System.out.println(new Date().getTime() - startTime);
- // 批量复制,最快
- startTime = new Date().getTime();
- array3.addAll(array1);
- System.out.println(new Date().getTime() - startTime);
- // 克隆,次快
- startTime = new Date().getTime();
- array4 = (ArrayList<Integer>) array1.clone();
- System.out.println(new Date().getTime() - startTime);
- array4.set(0, 4);
- System.out.println("array1[0]=" + array1.get(0));
- System.out.println("array4[0]=" + array4.get(0));
- }
- /*
- * 复制Map最好用逐个复制最快,putAll最简单
- * @author yifangyou
- * @since 2011-08-16 09:35:00
- */
- static void copyMap() {
- int maxlen = 1000000;
- Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();
- Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
- Map<Integer, Integer> map3 = new HashMap<Integer, Integer>();
- Map<Integer, Integer> map4 = new HashMap<Integer, Integer>();
- for (int i = 0; i < maxlen; i++) {
- map1.put(i, i);
- }
- long startTime;
- // 逐个复制,最快
- startTime = new Date().getTime();
- Set<Integer> key = map1.keySet();
- for (Iterator it = key.iterator(); it.hasNext();) {
- Integer k = (Integer) it.next();
- map2.put(k, map1.get(k));
- }
- System.out.println(new Date().getTime() - startTime);
- // 批量复制,最慢
- startTime = new Date().getTime();
- map3.putAll(map1);
- System.out.println(new Date().getTime() - startTime);
- System.out.println("map2[9999]=" + map2.get(9999));
- System.out.println("map3[9999]=" + map3.get(9999));
- // 逐个复制,次快
- startTime = new Date().getTime();
- Set<Map.Entry<Integer, Integer>> set = map1.entrySet();
- for (Iterator<Map.Entry<Integer, Integer>> it = set.iterator(); it
- .hasNext();) {
- Map.Entry<Integer, Integer> entry = (Map.Entry<Integer, Integer>) it
- .next();
- map4.put(entry.getKey(), entry.getValue());
- }
- System.out.println(new Date().getTime() - startTime);
- }
- }
复制代码 |
|