[推荐]甲骨文官网Java故障排查向导

甲骨文官网的Java故障排查向导比较全面地总结了面对各种Java故障时,该如何应对。推荐给大家。

Java平台 标准版 故障排查 向导 

下面摘要部分链接:

2 Diagnostic Tools

3 Troubleshoot Memory Leaks

Part II Debug JVM Issues

5 Troubleshoot System Crashes

6 Troubleshoot Process Hangs and Loops

7 Handle Signals and Exceptions

17 Submit a Bug Report

Part VI Appendix

A Fatal Error Log

C Environment Variables and System Properties

D Command-Line Options

E Summary of Tools in This Release

20160821关于g1讨论整理

莫简豪 20:26

many people curious about g1. Most apps still use cms. How does g1 perform in real production?

@Martijn Verburg @Monica Beckwith  hope you can give us some infomation

Monica Beckwith 21:01

Sure. If you have any specific use cases I can help. All companies that I worked with, that are able to get to latest JDK 8 release are happy moving to G1… with minimal tuning.

Martijn Verburg 21:34

Kirk and I are presenting our tuning G1 talk at JavaOne. I will post some of our current findings here over the weekend. We have found some usage patterns and edge cases where G1 has some challenges. It also is a good idea to track the open issues on the OpenJDK JIRA labelled with G1. You will see that there are many small fixes and improvements to go.

We would only recommend it for Java 8u91 as there are still JVM crash bugs prior to that

Humongous objects still cause big problems and there are hard limits to reference processing and object copy times depending on the shape of your object graph

ayanamist 22:08

Will g1gc has the ability to do parallel fullgc? Google has a patch for cms to enable parallel fullgc which brings quite a lot enhancement.

e.g. HBase, using BlockCache & MemStore, consumes a lot of heap space, and eventually has a fullgc after not a long time, which affects service availability when heap is large than 100GB. So concurrent fullgc is valuable in this case.

Martijn Verburg 22:18

IIRC the G1 full GC is currently single threaded but they are working on making it parallel. It is not concurrent by design (it has to stop all threads at a safe point). Monica will correct me if I’m wrong 🙂

I’m not yet convinced that G1 works all that well for heaps > 75GB. In *theory* a fully production read Shenandoah will perform better and of course the C4 collector still wins hands down.

That said there are still ~50 G1 bugs and features that they are working on, so I expect it it improve

Monica Beckwith 22:20

I have worked with Hbase and blockcache and memstore with G1 with about 64Gs no full GCs

Martijn Verburg 22:20

Yeah we typically see 64GB heaps for that sort of work

But unless you’re on the latest 8 update we’ve seen instabilities over several weeks of hot running

And of course with G1 the big question is what pause time goals you want 🙂. It’s a great low pause collector but not a low latency low pause collector (if you’re in the high frequency trading business)

Monica’s work on G1 is putting many of us out of a job 😉

One last note before I jump on my next plane. You can still get better extreme low latency out of a well tuned CMS than you can G1. However it takes a lot of work and tuning of many parameters.

This is why RedHat, Google, Twitter, ourselves and a few others will try to maintain CMS for Java 10 – but I think G1 will take over for a majority of applications who want good low pause behaviour with minimal tuning

Monica Beckwith 22:35

Agreed on low latency CMS surpasses G1 because you don’t have any old gen “collection” and you can easily avoid/push off full GCs…

(With CMS)

BTW, yes all full GCs in HotSpot are stop the world and so far only Parallel GC employs multiple threads for full collections

ayanamist 22:57

Param tuning is not a big problem in many company, but the best gc effect after tuning is.

Monica Beckwith 23:00

Ok. I understand. What is the live data set size for your 100g heap?

ayanamist 23:00

Yes we do not encounter fullgc on 64GB heap with forked but not community hbase 0.94 even on openjdk 6. But since larger heap brings out more problems, our hbase team is splitting hbase server to small unit using docker to decrease heap size.

@Monica Beckwith Also large than 64G. We have some 196G mem machines.

Reducing heap size and increasing unit count is not a ideal solution. It brings more work on operation and more mem overhead. So if jdk can improve its full gc performance, it will bring a lot wonderful things.

Monica Beckwith 23:04

Ok. We can work on this via email if you prefer… but if you could send more information on LDS and marking threshold and occupancy… it will give me a better idea of the workload pressure on G1

ayanamist 23:09

@Monica Beckwith Fine, i will forward this to our hbase team

Martijn Verburg 23:29

And please do grab a free trial copy of censum from Jclarity.com – it will help you compare and contrast your GC behaviour before and after changes.

java8 API (一) (String、正则、IO、集合)

前言

目的

  • java8自14年发布已经过去2年多了,越来越多的应用,开始升级到java8,升级不是目的,目的是升级之后,我们就可以使用java8新增的特性,从而提高开发效率、性能、稳定性等。所以伴随着升级,在团队内分享了java8的新特性,不过光了解新特性,知道lambda是啥,真正实践的时候还是有些迷茫(我自己现在就是这样),所以最近开始慢慢的整理java8新增的api,一方面字节在学习,另一方面通过例子的形式,希望可以帮助大家了解新增的api,以及api如何与lambda&stream等新特性应用在开发中。文章中不包含的内容:
    • java8新特性和语法讲很少,如果对java8还不太了解可以先自己查阅学习。
    • 文中例子都比较简单,代码以lambda和stream的代码为主,java8之前的代码例子基本没有,脑补一下,大家都能想出来。
  • 文中例子,都是自己敲过一遍,并且运行出的结果,如果大家发现问题,或者有更好的例子等都欢迎大家随时反馈给我@有光。

java8新增的API

  • 非官方数据
    • 195个新的文件加入到 JDK8 API
    • 93 新类, 89 新接口 , 13 新enum
    • 2699 新方法, 56 新构造函数
    • 46 个接口标记为函数式接口
    • 213 接口默认方法
    • 68 接口静态方法

基础

String

join()

  • 字符串拼接。
        String.join(":", "alibaba", "icbu", "youguang");
        String join = String.join(":", Lists.newArrayList("alibaba", "icbu", "youguang"));
        System.out.println(join);// => alibaba:icbu:youguang

chars()

  • 创建一个字符流。
  • 例子:统计去重后的字符数.
        long collect = "alibaba:icbu:youguang".chars()//
                                              .distinct()//
                                              .count();
        System.out.println(collect);// => 11

StringJoiner

  • 字符串拼接。
  • PS:String.join方法内部就是用StringJoiner实现的。
         StringJoiner sj = new StringJoiner(":");
        sj.add("alibaba");
        sj.add("icbu");
        sj.add("youguang");
        String result = sj.toString(); //alibaba:icbu:youguang

        sj = new StringJoiner(":","prefix-", "-suffix");
        sj.add("alibaba");
        sj.add("icbu");
        sj.add("youguang");
        System.out.println(sj.toString()); //prefix-alibaba:icbu:youguang-suffix

正则

Pattern.splitAsStream()

  • 正则分割后的结果,通过流来操作。
  • 例子:冒号分割,过滤掉youguang
        String bar = Pattern.compile(":")
                            .splitAsStream("alibaba:icbu:youguang")
                            .filter(s -> !s.contains("youguang"))
                            .collect(Collectors.joining(":"));
        System.out.println(bar);// => alibaba:icbu

Pattern.asPredicate()

  • 通过正则生成Predicate。
  • 例子:结合stream来过滤字符串。
      Pattern pattern = Pattern.compile(".*@gmail\\.com");
        Stream.of("tony.liw@gmail.com", "tony.liw@alibaba-inc.com")
              .filter(pattern.asPredicate())
              .count();// => 1

数学操作

输入&输出

  • java8提供了更简单的方式进行文件操作。

Files.list

  • Files类从1.7引入,1.8增加list方法生成stream来操作文件/目录。
  • PS:此处使用了1.7中的try-with-resource语法(Stream实现了AutoCloseable接口)
        try (Stream<Path> stream = Files.list(Paths.get("/opt"))) {
            String joined = stream.map(String::valueOf)//
                    .filter(path -> !path.startsWith("."))//
                     .sorted().collect(Collectors.joining("; "));
            System.out.println("List: " + joined);// => List: /opt/cisco; /opt/local

Files.find

  • 查找文件
  • 例子: 找到目录下的所有JavaScript文件(目录查找深度不超过5)。
        Path start = Paths.get("/home/admin/");
        int maxDepth = 5;//目录树层数
        try (Stream<Path> stream = Files.find(start, maxDepth, (path, attr) ->
                String.valueOf(path).endsWith(".js"))) {

            String joined = stream
                    .sorted()
                    .map(String::valueOf)
                    .collect(Collectors.joining("; "));
            System.out.println("Found: " + joined);
        }

Files.walk

  • 遍历文件,下面例子实现与上面的find同样的功能,不同的是过滤JavaScript文件通过stream的filter实现。
        Path start = Paths.get("/home/admin/");
        int maxDepth = 5;//目录树层数
        try (Stream<Path> stream = Files.walk(start, maxDepth)) {
            String joined = stream
                    .map(String::valueOf)
                    .filter(path -> path.endsWith(".js"))
                    .sorted()
                    .collect(Collectors.joining("; "));
            System.out.println("walk(): " + joined);
        }

Files.readAllLines

  • 读取文件的所有内容
List<String> lines = Files.readAllLines(Paths.get("res/nashorn.js"));
lines.add("print('foobar');");
Files.write(Paths.get("res/nashorn1-modified.js"), lines);

PS:使用该方法的时候要考虑到文件的大小,该方法会将所有内容一次读入内存。

Files.lines

  • 将文件内容转成stream,元素是每行的内容。
       try (Stream<String> stream = Files.lines(Paths.get("res/nashorn.js"))) {
            stream
                    .filter(line -> line.contains("print"))
                    .map(String::trim)
                    .forEach(System.out::println);
        }

Files.newBufferedReader&Files.newBufferedWriter

  • 带buffer的读写操作
Path path = Paths.get("res/nashorn1.js");
try (BufferedReader reader = Files.newBufferedReader(path)) {
    System.out.println(reader.readLine());
}
Path path = Paths.get("res/output.js");
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
    writer.write("print('Hello World');");
}

NULL(空指针)

  • 如何避免NullPointerException,为了避免NPE,写代码过程!=null检查会出现在各种地方,java8引入了更好的解决方案(Optional+Lambda)。其他语言解决NPE的语法糖

Optional基本

    //不要这样,这与!=null没什么区别
    if(stringOptional.isPresent()){
         System.out.println(stringOptional.get().length());
    }
    //下面是推荐的常用操作

    optionalValue.ifPresent(s -> System.out.println(s + " contains red"));
    //增加到集合汇总
    optionalValue.ifPresent(results::add);
    //增加到集合中,并返回操作结果
    Optional<Boolean> added = optionalValue.map(results::add);

    //无值的optional
    Optional<String> optionalString = Optional.empty();
    //不存在值,返回“No word”
    String result=optionalValue.orElse("No word");
    //没值,计算一个默认值
    result = optionalString.orElseGet(() -> System.getProperty("user.dir"));
    //无值,抛一个异常
    try {
        result = optionalString.orElseThrow(NoSuchElementException::new);
    } catch (Throwable t) {
    }   

Optional.map

  • 例子:看代码应该秒懂了,就是取foo值,但是为了取这个值,正常的逻辑里面需要增加一串!=null检查。java8中可以通过map函数避免。
//老的写法
Outer outer = new Outer();
if (outer != null && outer.nested != null && outer.nested.inner != null) {
    System.out.println(outer.nested.inner.foo);
}
//新的写法
Optional.of(new Outer())
    .map(Outer::getNested)
    .map(Nested::getInner)
    .map(Inner::getFoo)
    .ifPresent(System.out::println);

//第二种lambda的方式
resolve(() -> obj.getNested().getInner().getFoo())
    .ifPresent(System.out::println);

public static <T> Optional<T> resolve(Supplier<T> resolver) {
    try {
        T result = resolver.get();
        return Optional.ofNullable(result);
    }
    catch (NullPointerException e) {
        return Optional.empty();
    }
}

集合

Collection

removeIf

  • 通过传入Predicate删除集合里面符合条件的元素。
        Collection<String> c = new HashSet<>();
        c.add("Content 1");
        c.add("Content 2");
        c.add("Content 3");
        c.removeIf(s -> s.contains("2"));
        System.out.println(c);// => [Content 3, Content 1]
  • PS:如果这个接口可以满足过滤的要求,就没必要使用stream了,这个效率更好。
  • 扩展:充分利用Predicate,直接看例子
//基本操作
 list =new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10,11));
 list.removeIf(a->{ return a%3==0;});

 //OR 操作
 Predicate<Integer> predicate2 = a->{ return a % 3 == 0;};
 Predicate<Integer> predicate3 = a->{ return a % 5 == 0;};
 list =new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10,11));
 list.removeIf(predicate2.or(predicate3));

 //AND 操作
 Predicate<Integer> predicate2 = a->{ return a % 3 == 0;};
 Predicate<Integer> predicate3 = a->{ return a % 5 == 0;};
 list =new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10,11));
 list.removeIf(predicate2.and(predicate3));

stream、parallelStream

  • 大家都知道了,就不说了,记住所有集合类都是通过Collection接口继承来即可。

Iterable

forEach

  • 遍历每个元素,继承了Iterable接口的都可以使用。
 List<String> stringList = Arrays.asList("a", "b");
        stringList.forEach(System.out::println);

iterator

forEachRemaining

  • 遍历iterator,并根据指定的action进行处理。开发中可能会出现,需要对集合中的第一个或者前几个元素进行特别的操作,然后继续遍历剩余的元素执行另一个操作(action),这个时候使用forEachRemaining非常合适。例如下面字符串拼接的例子。
        if (!iterator.hasNext()) {
            return;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(iterator.next());
        iterator.forEachRemaining( element -> {
            builder.append(", ").append(element);
        });
  • PS:这里只是说明一下用法,字符串拼接,当然用String.join就够啦。

List

replaceAll

  • 传入UnaryOperator,将元素替换为一元操作之后的值
   List<String> stringList = Arrays.asList("a", "b", "c");
        stringList.replaceAll(String::toUpperCase);
        System.out.println(stringList);//[A, B, C]

sort

  • 通过指定Comparator进行排序,参数为空则根据自然排序。
        List<String> stringList = Arrays.asList("a", "b", "c");
        stringList.sort(String::compareTo);
  • PS: 可能会有人问这个和Collections.sort()的区别。下面是Collections的sort方法代码。内部调用的就是list.sort
  public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

Set

  • 接口没什么变化。

Map

foreach

       Map<String, Integer> map = new HashMap<>();
        map.put("A", 10);
        map.put("B", 20);
        map.put("C", 30);
        map.forEach((k, v) -> System.out.println("Item : " + k + " Count : " + v));

getOrDefault

  • 根据key取value,没有返回一个默认值(这个一直是很多人想要的方法)。
System.out.println(map.getOrDefault("D",40));// => 40
  • PS:如果还在使用Apache Commons Collections包中的DefaultedMap类,更换了。

putIfAbsent

  • javadoc中提供了与putIfAbsent的等价方法,
  • 特别说明put方法返回值:对应的key曾经有值返回老的value,否则返回null
    //The default implementation is equivalent to, for this map:
       V v = map.get(key);
      if (v == null)
          v = map.put(key, value);
    
      return v;
    
  • 例子:
        System.out.println(map.putIfAbsent("B",40));// => 20
        System.out.println(map.putIfAbsent("D",40));// => null
    

remove(Object.Object)

  • key和valu都相等的时候才删除,下面是javadoc中原来等价方法实现。
      if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
          map.remove(key);
          return true;
      } else
          return false;
  • 例子:
 System.out.println(map.remove("D",40));// => true

replace(K,V)

  • map中包含这个key,替换对应的value。javadoc中原来等价的方法实现
      if (map.containsKey(key)) {
          return map.put(key, value);
      } else
          return null;
  • 例子:Map<String, Integer> map = new HashMap<>(); map.put("A", 10); System.out.println(map.replace("A",20));//=> 10
  • PS:注意与putIfAbsent区别

replace(K,V,V)

  • map中包含这个key,并且value相等时,替换对应的value。javadoc中原来等价的方法实现
      if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
          map.put(key, newValue);
          return true;
      } else
          return false;
  • 例子:
        Map<String, Integer> map = new HashMap<>();
        map.put("A", 10);
        map.put("B", 20);
        System.out.println(map.replace("B",10,100));//=>false
        System.out.println(map.replace("B",20,100));//=> true

compute(K,remappingFunction)

  • 通过remappingFunction函数,根据指定的key和对应的value,通过计算生成新的value。javadoc中原来等价的方法实现
      V oldValue = map.get(key);
      V newValue = remappingFunction.apply(key, oldValue);
      if (oldValue != null ) {
         if (newValue != null)
            map.put(key, newValue);
         else
            map.remove(key);
      } else {
         if (newValue != null)
            map.put(key, newValue);
         else
            return null;
      }
  • 例子:统计单词出现次数/统计图书借阅次数/遇到同样的key,创建或者append一个msg信息等。
        Map<String, Integer> countMap = Maps.newHashMap();
        List<String> bookList= Arrays.asList("Book-A", "Book-B", "Book-A");
        for (String book : bookList) {
            countMap.compute(book, (k, v) -> v == null ? 1 : v + 1);
        }
        System.out.println(countMap);
  • PS:要注意如果remappingFunction计算结果为空,会从map中remove

computeIfAbsent(K,mappingFunction)vs computeIfPresent(K,remappingFunction)

  • 这两个方法比较相近容易混淆,对比一下,下面是javadoc中两个新方法等同老代码。左侧:computeIfAbsent,右侧:computeIfPresent screenshot
  • 区别:
    • computeIfAbsent value根据key计算。computeIfPresent value基于key和oldValue计算(参数名也可以看出点意思mappingFunction/remappingFunction)
    • newValue为空,computeIfPresent会删除map中的元素。
  • 例子:这两个方法很容易想到的一个场景是本地缓存(考虑到多线程场景可以使用ConcurrentHashMap),下面以computeIfAbsent方法为例,同时与java8之前的版本代码做一下对比。
    
    static Map<String, Integer> CACHE = new ConcurrentHashMap<>();
    
    public Integer  getJAVA8(String key){
        //java8会使用thread-safe的方式从cache中存取记录
       return CACHE.computeIfAbsent(key, s -> {
           int rt=0;
           //xxx 计算 rt=
           return rt;
       });
    }
    
    public Integer  getJAVA7(String key){
    
        Integer rt = CACHE.get(key);
    
        if (rt == null) {
            //java8 中ConcurrentHashMap复写了computeIfAbsent方法做了线程安全控制
            synchronized (CACHE) {
                rt = CACHE.get(key);
                if (rt == null) {
                    //xxxx计算 rt=
                    CACHE.put(key, rt);
                }
            }
        }
        return rt;
    }
    

merge(K,V,remappingFunction)

  • 看名字已经理解80%了,直接看javadoc中与老版本等价的代码好了。
      V oldValue = map.get(key);
      V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
      if (newValue == null)
          map.remove(key);
      else
          map.put(key, newValue);
  • 是不是一眼看过去和computeIfPresent很像。此处diff一下就清晰了,computeIfPresent是在key对应的value存在时才有效。 screenshot

replaceAll(function)

  • 根据function计算结果,替换map所有entry的value

Comparator

  • Comparator在平时开发中用的比较多,java8针对该接口,增加了16个默认方法和静态方法,下面挑一些跟大家分享。

comparing(keyExtractor)

  • 先看例子,生成根据firstName对Person进行排序的Comparator:
        //老写法
        Comparator<Person> comparator=new Comparator<Person>() {
    
            @Override
            public int compare(final Person o1, final Person o2) {
                return o1.name.compareTo(o2.name);
            }
        };
        //lambda 写法
        comparator= (o1, o2) -> o1.name.compareTo(o2.name);
        //Comparator.comparing方法,提供提取比较key的function即可
        comparator= Comparator.comparing(Person::getName);
    
  • PS:该方法,要求提取的key实现了 Comparable接口。key没有Comparable接口可以使用重载实现comparing(keyExtractor,keyComparator)
  • 重载方法:
    • comparing(keyExtractor,keyComparator)
    • comparingInt(keyExtractor) 提取的key是Integer类型
    • comparingLong(keyExtractor)
    • comparingDouble(keyExtractor)

reversed()

  • 反转比较规则
        List<Integer> integerList = Arrays.asList(1, 3, 2, 5, 4);
        //正序
        integerList.sort(Integer::compareTo);
        System.out.println(integerList); // => [1, 2, 3, 4, 5]
        //倒序
        integerList.sort(Comparator.comparing(Integer::intValue).reversed()); // => [5, 4, 3, 2, 1]

thenComparing(other)

  • 链式比较,以后不用在使用第三方的ComparisonChain类了。
  • 例子:先按字符串长度,再按字符默认顺序排序(忽略大小写)。
 Comparator<String> cmp = Comparator.comparingInt(String::length)
                                              .thenComparing(String.CASE_INSENSITIVE_ORDER);
  • 重载方法
    • thenComparing(keyExtractor,keyComparator)
    • thenComparing(keyExtractor)
    • thenComparingInt(keyExtractor)
    • thenComparingLong(keyExtractor)
    • thenComparingDouble(keyExtractor)

reverseOrder

  • 静态方法,返回与自然排序相反的Comparator(比较元素要实现Comparator接口)
        List<Integer> integerList2 = Arrays.asList(1, 3, 2, 5, 4);
        integerList.sort(Comparator.reverseOrder());
        System.out.println(integerList);// => [5, 4, 3, 2, 1]

naturalOrder

  • 与reverseOrder相反,默认的自然排序器。等价//c1.compareTo(c2);

nullsFirst(comparator) & nullsLast(comparator)

  • 针对null值指定策略,排在前面(nullsFirst),还是后面(nullsLast)
        List<Integer> integerList3 = Lists.newArrayList(1, 3, null, 5, 4);
        integerList3.sort(Comparator.nullsFirst(Integer::compareTo));
        System.out.println(integerList3);// => [null, 1, 3, 4, 5]
        integerList3.sort(Comparator.nullsLast(Integer::compareTo));
        System.out.println(integerList3);// => [1, 3, 4, 5, null]
  • 这两个比较器一个很大的作用是可以处理结合中有null值的情况,一般默认的比较器遇到null都会抛出NPE,如果不想NPE可以使用nullsFirst/nullsLast包装一下。上面例子:如果不通过Comparator.nullsFirst(Integer::compareTo)生成新的比较器,直接使用Integer::compareTo就会抛NPE异常。

Arrays

  • 工具类中增加了一些对数组相关的流和并行处理的操作。

Stream

  • 将数组转成流进行操作,这样Stream Api就都可以用了stream api
//数组内容求和
int[] array = new int[]{1,2,3,4,5};
//求和
Arrays.stream(array).sum()
//过滤
int[] ms = Arrays.stream(ns).map(n -> n * 2).filter(n -> n % 4 == 0).toArray();

setAll

  • setAll方法提供一个 int -> T的函数接口做参数,int是数组的索引,T是数组的新值。
  • 例子:通过该接口对数组的索引进行操作,然后将指定数组当前索引位置的值赋值为操作后的值。
        int[] array = new int[10];
        Arrays.setAll(array, i -> i * 10);
        System.out.println(Arrays.toString(array));// => 输出 [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]        

spliterator

Collections

  • emptySortedSet、emptySortedMap、emptyNavigableSet、emptyNavigableMap、unmodifiableNavigableSet、unmodifiableNavigableMap、synchronizedNavigableSet、synchronizedNavigableMap等。

集合&数组转化

数组转集合

  • 没发现java8有什么新增的方式,如果有同学知道的求推荐。老的方式(Arrays/Guava包):
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4);
        // guava
        integerList = Lists.newArrayList(1, 2, 3, 4);

集合转数组

  • 看例子
        //原始方式
        Integer[] integerArray = integerList.toArray(new Integer[integerList.size()]);
        // guava
        int[] intArray = Ints.toArray(integerList);
        // java8-基本类型
        intArray = integerList.stream().mapToInt(Integer::intValue).toArray();
         // java8-对象类型
        stringArray = stringList.stream().toArray(String[]::new);
Character[] characterArray = stringList.stream().map(s -> s.charAt(0)).toArray(Character[]::new);

未完待续

  • java8 API (二) stream整理中

推荐一个终端获取jmx信息的小工具——jmxterm

作者@JianhaoMo

最近由于某些原因跟同学推荐了下jmxterm,发现还是不少同学不知道有这么个工具,所以在这里推荐下。

官网:http://wiki.cyclopsgroup.org/jmxterm/

jmxterm是本地命令行看jmx的工具,jdk7以上自带的jcmd命令可以动态打开关闭本地jmx

举例看codecache:

jcmd <pid> ManagementAgent.start_local

echo “get -d java.lang -b name=Code\ Cache,type=MemoryPool Usage” |  java -jar jmxterm-1.0-alpha-4-uber.jar -l <pid> -v silent -n

jcmd <pid> ManagementAgent.stop

fastjson 1.2.10版本发布,修复Bug,支持Class Level SerializeFilter

作者:温绍锦(@温高铁)阿里巴巴资深技术专家

Bug Fixed

  1. 修复ValueFilter导致序列化数据丢失的问题,这个在1.2.9优化序列化引起。
  2. 修复某些场景下解析json中的注释出错。issue 559
  3. 修复WriteNonStringValueAsString特性打开时,非public类序列化会导致int类型输出为0的问题。 issue 572
  4. 修复1.2.8/1.2.9版本不支持JDK 1.5的问题

功能增强

  1. 新增Class Level SerializeFilter支持,在此之前只能在toJSONString时SerializeFilter,对所有的类型都起作用,这样会对框架的实现由性能影响,新特性允许SerializeFilter注册在类型上,具体文档看这里https://github.com/alibaba/fastjson/wiki/Class_Level_SerializeFilter

相关链接

获取一直FullGC下的java进程HeapDump的小技巧

作者:@善良的右席

小技巧

我们应用的java进程出问题的时候,我们往往会用jmap或者gcore拿到一份HeapDump,拿到MAT上做一次Heap分析,但是 如果你排查的是一直在FullGC的gc问题,你Dump下来的堆往往是正处于FullGC中,可能会导致分析失败。@坤谷 发现了一个小技巧,可以dump下完整而且没有在被移动中的Heap。

操作流程

  • 找到java进程,gdb attach上去, 例如 gdb java -p 22443
  • 找到这个HeapDumpBeforeFullGC的地址(这个flag如果为true,会在FullGC之前做HeapDump,默认是false)
    (gdb) p &HeapDumpBeforeFullGC
    $2 = (<data variable, no debug info> *) 0x7f7d50fc660f <HeapDumpBeforeFullGC>
    
  • 然后把他设置为true,这样下次FGC之前就会生成一份core文件
    (gdb) set *0x7f7d50fc660f = 1
    (gdb) quit
    
  • 最后,等一会,等下次FullGC触发,你就有HeapDump了!

(PS. jstat -gcutil pid 可以查看gc的概况)

 

注意事项,设完,观察heapdump生成路径和磁盘,别生成太多,让磁盘满了,heapdump出来后,及时kill掉应用。

 

Q&A
Q1:把HeapDumpAfterFullGC也设上是不是会更快点儿?
A1:那就是被fullgc完之后的堆了,会不会堆里有些业务垃圾会有助于分析嘛。。

Q2: HeapDumpBeforeFullGC 可以用JCMD改的吧, 我看是manageable 属性
A2: 是的,如果jcmd,jinfo能改,就先用工具。这里是所有别的工具都失败的情况下的办法。一直fullgc的时候jinfo会不生效吧

Q3: jmx,mxbean能直接动态改的,比如去Jconsole里setVmOption,直接将HeapDumpBeforeFullGC和HeapDumpAfterFullGC设置成true,也比较方便的A3: 嗯嗯是的,但是这类方法缺点就是如果应用一直无限fullgc,会导致修改不成功

Q4: 一直fgc,用jmap -histo,我觉得就基本上能看出蛛丝马迹了
A4: 不错。其实很多时候还不需要heapdump,taobao-jdk6/ali-jdk8/ajdk8的大数组警告,直接能看出问题。

Q5: jmap -F 不行吗
A5: 那个时候dump下来的堆,可能正处于gc中,会解析失败

Q6: 文章中不是说等下次full gc吗?既然等到下一次full gc,我觉得jmap -F能dump出文件吧?或者直接设置jvm -XX:+UseHeapDumpBeforeFullGC应该也可以吧?不知道说的对不对
A6: jmap -F的原理和gcore差不多,强行dump出内存,这个时候如果正在gc中,那么内存中对象的引用关系可能是乱的。XX:+UseHeapDumpBeforeFullGC这个flag,线上应用肯定是不会开的。上面的方法就是强制打开这个flag