Java优化 - 领域对象

Domain objects表达程序里的业务概念。比如电子商务系统里的Order、OrderItem和DeliverySchedule。这些类型之间有相关关系(Order可以包含多个OrderItem实例)。例如:

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
public class Order {
   private final long id;
   private final List<OrderItem> items = new ArrayList<>();
   private DeliverySchedule schedule;

   public Order(long id) {
      this.id = id;
   }

   public DeliverySchedule getSchedule() {
      return schedule;
   }

   public void setSchedule(DeliverySchedule schedule) {
      this.schedule = schedule;
   }

   public List<OrderItem> getItems() {
      return items;
   }

   public long getId() {
      return id;
   }
}

public class OrderItem {
   private final long id;
   private final String description;
   private final double price;

   public OrderItem(long id, String description, double price) {
      this.id = id;
      this.description = description;
      this.price = price;
   }

   @Override
   public String toString() {
      return "OrderItem{" + "id=" + id + ", description=" +
            description + ", price=" + price + '}';
   }
}

public class DeliverySchedule {
   private final LocalDate deliveryDate;
   private final String address;
   private final double deliveryCost;

   private DeliverySchedule(LocalDate deliveryDate, String address,
                      double deliveryCost) {
      this.deliveryDate = deliveryDate;
      this.address = address;
      this.deliveryCost = deliveryCost;
   }

   public static DeliverySchedule of(LocalDate deliveryDate, String address,
                             double deliveryCost) {
      return new DeliverySchedule(deliveryDate, address, deliveryCost);
   }

   @Override
   public String toString() {
      return "DeliverySchedule{" + "deliveryDate=" + deliveryDate +
            ", address=" + address + ", deliveryCost=" + deliveryCost + '}';
   }
}

可以看到,领域类型之间有所有权关系,见下图。当然,领域对象图的叶子节点,大部分是简单的数据类型,比如字符串、原始类型和LocalDateTime。
Domain objects graph

使用jmap -histo命令,可以查看堆内状态,当然,也可以使用GUI工具,比如VisualVM。学习这些工具,可以诊断领域对象的内存泄漏情况。
另一个常见的领域对象泄漏行为是“所有代”效应-特定类型的对象没有被回收。这意味着他们会存活足够长时间成为Tenured,经过足够多的survive回收之后,有很大的代计数(generational count)。
如果我们绘制每个代计数的每个数据类型的字节数量的直方图,可以看到泄漏的领域对象跨越所有的代。应该查看领域对象相关的数据集的大小,看这些值是否合理。
而短期存活的领域对象能导致浮动垃圾问题。回想一下并发回收的SATB约束-如果在标记周期开始后分配的对象,无论有多短命,也被认为是活的。领域对象泄漏能导致高的GC标记时间,根本原因是单个长期存活的对象会让整个对象链长期存活。

原文地址:https://blog.csdn.net/weixin_43364172/article/details/86519616?ops_request_misc=&request_id=7358bddffa5a4b5a842fdc40cf8ff8c5&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2~all~koosearch~default-2-86519616-null-null.142^v88^insert_down28v1,239^v2^insert_chatgpt&utm_term=java%E4%BC%98%E5%8C%96