Skip to content

[BUG]getShort等类型,每次都会spin一次,cpu飙升 #7677

Description

@wongjjjyi-create

问题描述

com.alibaba.fastjson2.introspect.PropertyAccessorFactoryLambda#getByte的getInt(method) 这个调用被写在了 lambda 的方法体内部。而 getInt(method) 本身就是"会 spin 一个新 lambda"的操作(它内部调 LambdaMetafactory.metafactory 造 int 取值器)。

导致序列化一百万次 flag → getInt 被调 100 万次 → spin 100 万次 → $$Lambda$ 编号飙到 150 万

环境信息

  • OS信息: Linux host-11-18-140-48 3.10.0-693.5.2.el7.jd_3313.x86_64 修复Readme的Codeconv配置 #1 SMP Wed May 2 14:35:41 CST 2018 x86_64 x86_64 x86_64 GNU/Linux
  • JDK信息: Openjdk 1.8.0_312
  • 版本信息:fastjson2 4.0.0

重现步骤

不断调用 ComplexPoJo2 sample = getIPBeanParentPOJO(new ComplexPoJo(), strlength);
logger.info("bigInfo payload: {}", LogUtils.dump(sample));进行日志打印,
其中getIPBeanParentPOJO为
@OverRide
public ComplexPoJo2 getIPBeanParentPOJO(ComplexPoJo beanParent,int length) throws InterruptedException {

    ThreadLocalRandom r = ThreadLocalRandom.current();
    ComplexPoJo2.Status[] statuses = ComplexPoJo2.Status.values();

    ComplexPoJo2 resp = new ComplexPoJo2();

    // 基本类型
    resp.setId(r.nextInt(1, 100000));
    resp.setTimestamp(System.currentTimeMillis() - r.nextLong(0, 86400_000L));
    resp.setScore(r.nextDouble(0.0, 100.0));
    resp.setActive(r.nextBoolean());
    resp.setLevel((short) r.nextInt(1, 10));
    resp.setFlag((byte) r.nextInt(0, 128));

    // 字符串
    resp.setName("user-" + getRandomStringFast(8));
    resp.setDescription(getRandomStringFast(length));

    // 日期
    resp.setCreateTime(new Date(System.currentTimeMillis() - r.nextLong(0, 30L * 86400_000)));
    resp.setUpdateTime(beanParent.getCreateTime() != null ? beanParent.getCreateTime() : new Date());

    // BigDecimal
    resp.setAmount(BigDecimal.valueOf(r.nextDouble(1.0, 9999.99)).setScale(2, BigDecimal.ROUND_HALF_UP));

    // 枚举
    resp.setStatus(statuses[r.nextInt(statuses.length)]);

    // 数组
    byte[] bin = new byte[r.nextInt(16, 64)];
    r.nextBytes(bin);
    resp.setBinaryData(bin);
    int[] intArr = new int[r.nextInt(4, 12)];
    for (int i = 0; i < intArr.length; i++) intArr[i] = r.nextInt(0, 1000);
    resp.setIntArray(intArr);

    // List<String> tags
    int tagCount = r.nextInt(2, 6);
    List<String> tags = new ArrayList<>(tagCount);
    for (int i = 0; i < tagCount; i++) tags.add("tag-" + getRandomStringFast(4));
    resp.setTags(tags);

    // List<Integer> scores
    int scoreCount = r.nextInt(3, 8);
    List<Integer> scores = new ArrayList<>(scoreCount);
    for (int i = 0; i < scoreCount; i++) scores.add(r.nextInt(0, 100));
    resp.setScores(scores);

    // Set<String> categories
    int catCount = r.nextInt(2, 5);
    Set<String> categories = new HashSet<>(catCount);
    for (int i = 0; i < catCount; i++) categories.add("cat-" + getRandomStringFast(3));
    resp.setCategories(categories);

    // Map<String, String> attributes
    int attrCount = r.nextInt(2, 5);
    Map<String, String> attrs = new HashMap<>(attrCount);
    for (int i = 0; i < attrCount; i++) attrs.put("attr-" + i, getRandomStringFast(8));
    resp.setAttributes(attrs);

    // Map<String, Integer> counters
    int counterCount = r.nextInt(2, 5);
    Map<String, Integer> counters = new HashMap<>(counterCount);
    for (int i = 0; i < counterCount; i++) counters.put("counter-" + i, r.nextInt(0, 10000));
    resp.setCounters(counters);

    // Map<String, MetaEntry>
    int metaCount = r.nextInt(2, 4);
    Map<String, ComplexPoJo2.MetaEntry> metaMap = new HashMap<>(metaCount);
    for (int i = 0; i < metaCount; i++) {
        ComplexPoJo2.MetaEntry entry = new ComplexPoJo2.MetaEntry();
        entry.setKey("mk-" + i);
        entry.setValue(getRandomStringFast(12));
        entry.setCount(r.nextInt(1, 100));
        Map<String, String> extra = new HashMap<>(2);
        extra.put("ex1", getRandomStringFast(6));
        extra.put("ex2", getRandomStringFast(6));
        entry.setExtra(extra);
        metaMap.put("meta-" + i, entry);
    }
    resp.setMetaMap(metaMap);

    // 嵌套对象 AddressInfo
    resp.setAddress(randomAddress(r));

    // List<OrderItem>
    int itemCount = r.nextInt(2, 5);
    List<ComplexPoJo2.OrderItem> items = new ArrayList<>(itemCount);
    for (int i = 0; i < itemCount; i++) items.add(randomOrderItem(r));
    resp.setItems(items);

    // Map<String, List<OrderItem>>
    int groupCount = r.nextInt(2, 4);
    Map<String, List<ComplexPoJo2.OrderItem>> grouped = new HashMap<>(groupCount);
    for (int i = 0; i < groupCount; i++) {
        int gItemCount = r.nextInt(1, 4);
        List<ComplexPoJo2.OrderItem> gItems = new ArrayList<>(gItemCount);
        for (int j = 0; j < gItemCount; j++) gItems.add(randomOrderItem(r));
        grouped.put("group-" + i, gItems);
    }
    resp.setGroupedItems(grouped);

    return resp;
}

private ComplexPoJo2.AddressInfo randomAddress(ThreadLocalRandom r) {
    String[] cities = {"Beijing", "Shanghai", "Guangzhou", "Shenzhen", "Hangzhou", "Chengdu", "Wuhan"};
    ComplexPoJo2.AddressInfo addr = new ComplexPoJo2.AddressInfo();
    addr.setCountry("China");
    addr.setProvince("Province-" + getRandomStringFast(4));
    addr.setCity(cities[r.nextInt(cities.length)]);
    addr.setStreet("Street-" + r.nextInt(1, 999));
    addr.setZipCode(String.format("%06d", r.nextInt(100000, 999999)));
    addr.setLatitude(r.nextDouble(18.0, 53.0));
    addr.setLongitude(r.nextDouble(73.0, 135.0));
    return addr;
}

private ComplexPoJo2.OrderItem randomOrderItem(ThreadLocalRandom r) {
    ComplexPoJo2.OrderItem item = new ComplexPoJo2.OrderItem();
    item.setItemId("item-" + getRandomStringFast(6));
    item.setItemName("Product-" + getRandomStringFast(8));
    item.setQuantity(r.nextInt(1, 50));
    double unitPrice = r.nextDouble(1.0, 999.99);
    item.setUnitPrice(unitPrice);
    item.setTotalPrice(BigDecimal.valueOf(unitPrice * item.getQuantity()).setScale(2, BigDecimal.ROUND_HALF_UP));
    Map<String, String> props = new HashMap<>(3);
    props.put("color", getRandomStringFast(5));
    props.put("size", getRandomStringFast(3));
    props.put("brand", getRandomStringFast(6));
    item.setProperties(props);
    item.setDeliveryAddress(randomAddress(r));
    return item;
}

public static String getRandomStringFast(int length){
    final String pool="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    ThreadLocalRandom random=ThreadLocalRandom.current();
    char[] buf=new char[length];
    for(int i=0;i<length;i++){
        buf[i]=pool.charAt(random.nextInt(62));
    }
    return new String(buf);
}

期待的正确结果

压测后,性能不差于fastjson1.x

fastjson1和fastjson2火焰图

218363_20260710182318667.html
218368_20260710185516618.html

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions