Phát triển với Java thời gian thực, Phần 2: Cải thiện chất lượng dịch vụ Sử dụng Java thời gian thực để giảm bớt độ đa dạng trong các ứng dụng Java pptx

29 324 0
Phát triển với Java thời gian thực, Phần 2: Cải thiện chất lượng dịch vụ Sử dụng Java thời gian thực để giảm bớt độ đa dạng trong các ứng dụng Java pptx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Phát triển với Java thời gian thực, Phần 2: Cải thiện chất lượng dịch vụ Sử dụng Java thời gian thực để giảm bớt độ đa dạng trong các ứng dụng Java Mark Stoodley, Lãnh đạo Kỹ thuật Thời gian Thực WebSphere, IBM Toronto Lab Charlie Gracie, Lãnh đạo nhóm Máy ảo J9, IBM Tóm tắt: Một số ứng dụng Java™ không cung cấp được chất lượng hợp lý của dịch vụ mặc dù đạt được các mục tiêu hiệu năng khác, chẳng hạn như thời gian trễ trung bình hoặc thông lượng tổng thể. Bằng cách đưa ra các đoạn dừng hoặc ngắt không chịu kiểm soát của ứng dụng, ngôn ngữ Java và hệ thống thời gian chạy đôi khi có thể chịu trách nhiệm về không đáp ứng các độ đo hiệu năng của ứng dụng. Bài viết này là bài thứ hai trong loạt bài ba phần, giải thích nguồn gốc căn nguyên của trễ và ngắt trong một JVM và mô tả các kỹ thuật cho phép bạn có thể dùng để giảm thiểu các căn nguyên, nhằm ứng dụng của bạn cung cấp chất lượng dịch vụ ổn định hơn. Tính đa dạng trong một ứng dụng Java — thường gây ra do các đoạn dừng, hoặc trễ, xảy ra vào những lúc không thể đoán trước được — có thể xảy ra qua ngăn xếp phần mềm. Các trễ có thể xuất hiện do:  Phần cứng (trong các quá trình xử lý chẳng hạn như nhớ nhanh).  Phần đệm (xử lý của các ngắt quản lý hệ thống chẳng hạn như dữ liệu về nhiệt độ bộ xử lý trung tâm).  Hệ điều hành (trả lời một ngắt hoặc khai thác một hoạt động thông minh đã lên lịch thường kì).  Các chương trình khác chạy trên cùng hệ thống.  JVM (gom rác, biên dịch Đúng lúc, và tải lớp).  Chính ứng dụng Java. Bạn có thể hiếm khi bù lại ở một mức cao cho các trễ do mức thấp hơn gây nên, vậy nếu bạn cố gắng giải quyết độ đa dạng chỉ ở mức ứng dụng, có thể bạn chỉ cần chuyển đổi JVM hoặc các trễ của hệ điều hành ở đâu đó mà không giải quyết vấn đề thực. May mắn là các thời gian chờ đối với các mức thấp hơn có xu hướng tương đối ngắn hơn các thời gian chờ ở các mức cao, như vậy chỉ khi nào yêu cầu của bạn đối với việc giảm độ đa dạng là vô cùng nhiều thì bạn mới cần xem xét thấp hơn JVM hoặc hệ điều hành. Nếu các yêu cầu của bạn không nhiều đến như vậy, thì bạn có thể gần như chắc chắn tập trung đủ các cố gắng của bạn ở mức JVM và trong ứng dụng của bạn. Java thời gian thực cho bạn các công cụ mà bạn cần phải vật lộn với các tài nguyên biến đổi trong một JVM và trong các ứng dụng của bạn để cung cấp chất lượng dịch vụ mà những người sử dụng của bạn đòi hỏi. Bài viết này đề cập đến nguồn gốc của sự đa dạng ở các mức JVM và ứng dụng một cách chi tiết và mô tả các công cụ và kỹ thuật mà bạn có thể sử dụng để giảm nhẹ tác động của chúng. Sau đó nó đưa ra một ứng dụng máy chủ Java đơn giản trình bày một số khái niệm này. Nhằm vào các nguồn biến đổi Các nguồn biến đổi ban đầu trong một JVM xuất phát từ tính chất động của ngôn ngữ Java:  Bộ nhớ không giải phóng hiển hiện do ứng dụng mà thay vào đó được phục hồi theo định kỳ bởi bộ gom rác.  Các lớp được giải quyết khi ứng dụng sử dụng chúng đầu tiên.  Mã riêng được biên dịch (và có thể được biên dịch lại bằng một Bộ biên dịch Đúng lúc (Just-in-time (JIT) compiler) khi ứng dụng đang chạy, dựa trên các lớp và phương thức nào được gọi ra thường xuyên. Ở mức ứng dụng Java, việc quản lý các xử lí là lĩnh vực chủ yếu liên quan đến độ đa dạng. Đoạn dừng gom rác Khi bộ gom rác chạy để phục hồi bộ nhớ mà chương trình không còn sử dụng nữa, nó có thể dừng tất cả các xử lí ứng dụng. (Kiểu bộ gom này gọi là một bộ gom Stop-the-world (Dừng lại tất cả), hay bộ gom STW.) Hoặc nó có thể thực hiện một số công việc của mình đồng thời với ứng dụng. Trong trường hợp ấy, các tài nguyên mà bộ gom rác cần có cũng không đủ dùng cho ứng dụng, cho nên việc gom rác (GC) là nguyên nhân gây dừng và biến đổi đối với hiệu năng ứng dụng Java, như thường được biết đến. Mặc dù nhiều hình mẫu GC có các ưu điểm và nhược điểm của nó, khi mục tiêu đối với một ứng dụng là các đoạn dừng GC ngắn, hai lựa chọn chính là bộ gom sản sinh (generational) và và bộ gom thời gian thực (real-time). Các bộ gom sản sinh tổ chức đống thành ít nhất 2 phần thường gọi là không gian mới và không gian cũ (đôi khi gọi là theo nhiệm kỳ tenured). Các đối tượng mới luôn luôn được phân bổ trong không gian mới. Khi không gian mới hết bộ nhớ tự do, rác chỉ được thu gom trong không gian đó. Việc sử dụng một không gian mới tương đối nhỏ có thể giữ được thời gian chu trình GC khá ngắn. Các đối tượng qua được một số thu gom không gian-mới được thúc đẩy trở thành không gian cũ. Các thu gom không gian cũ thường ít xuất hiện hơn nhiều so với các thu gom không gian mới, nhưng do không gian cũ lớn hơn nhiều so với không gian mới, các chu trình GC này có thể mất nhiều thời gian hơn. Các bộ gom rác sản sinh đưa ra các đoạn dừng GC trung bình tương đối ngắn, nhưng chi phí của các thu gom không gian cũ có thể gây ra sai lệch chuẩn sau các lần đoạn dừng này sẽ là khá lớn. Các bộ gom sản sinh là hiệu quả nhất trong các ứng dụng mà tập hợp các dữ liệu sống không thay đổi nhiều theo thời gian nhưng nhiều rác được tạo ra. Trong kịch bản này, các thu gom không gian cũ là vô cùng hiếm, và như vậy các lần tạm ngừng GC là do các thu gom không gian cũ ngắn. Ngược lại với các bộ gom sản sinh, các bộ gom rác thời gian thực điều khiển hành vi của chúng để thu ngắn rất nhiều độ dài của chu trình GC (bằng cách khai thác các chu trình khi ứng dụng không dùng đến) hoặc để giảm bớt ảnh hưởng của các chu trình này về hiệu năng ứng dụng (bằng cách thực hiện công việc bằng các gia số nhỏ phù hợp với một “mức độ rút ngắn” với ứng dụng). Việc sử dụng một trong những bộ gom này cho phép bạn lường trước được trường hợp xấu nhất để hoàn tất một tác vụ riêng. Thí dụ, bộ gom rác trong các JVM thời gian thực IBM® WebSphere® chia các chu trình GC thành các việc nhỏ — gọi là các lượng tử GC (GC quanta ) — mà có thể được hoàn tất gia tăng. Việc lên lịch các lượng tử có một tác động vô cùng thấp về hiệu năng ứng dụng, với các trễ thấp đến phần trăm micro-giây nhưng thường nhỏ hơn 1 milli-giây. Để đạt được mức trễ này, bộ gom rác phải có khả năng lập kế hoạch công việc của nó bằng cách đưa ra khái niệm về một mức độ rút ngắn sử dụng ứng dụng. Mức độ rút ngắn này điều khiển mức độ thường xuyên mà GC được phép ngắt ứng dụng để thực hiện công việc của nó. Thí dụ, mức độ rút ngắn sử dụng mặc định là 70% mà chỉ cho phép GC sử dụng đến 3 mili-giây trong mỗi 10 mili-giây, với các đoạn dừng điển hình khoảng 500 micro- giây, khi chạy trên một hệ điều hành thời gian thực. (xem "Java thời gian thực, Phần 4: Gom rác Thời gian thực" để được mô tả chi tiết về phép gom rác Thời gian Thực WebSphere của IBM). Kích thước của đống và mức sử dụng ứng dụng là các tuỳ chọn điều chỉnh quan trọng cần cân nhắc khi chạy một ứng dụng trên một bộ gom rác thời gian thực. Khi mức sử dụng ứng dụng tăng lên, bộ gom rác nhận được ít thời gian hơn để hoàn tất công việc của nó, như vậy cần có đống lớn hơn để đảm bảo chu trình GC có thể được hoàn tất gia tăng. Nếu bộ gom rác không thể theo kịp với tốc độ phân bố, GC quay trở lại một thu gom đồng bộ. Thí dụ, một ứng dụng chạy trên các JVM thời gian thực WebSphere của IBM, với mức độ sử dụng ứng dụng mặc định 70% của chúng, đòi hỏi nhiều đống theo mặc định hơn nếu nó được chạy trên một JVM bằng cách sử dụng một bộ gom rác sản sinh (mà không đưa ra mức độ rút ngắn việc sử dụng. Do các bộ gom rác thời gian thực điều khiển thời lượng dừng GC, việc gia tăng kích thước của đống làm hạ tần suất GC mà không kéo dài thời gian tạm ngừng. Trong các bộ gom rác không phải thời gian thực, về mặt khác, việc gia tăng kích thước đống thường làm giảm bớt tần số của các chu trình GC, nó giảm bớt tổng thể tác động của bộ gom rác; khi một chu trình GC xuất hiện, thời gian đoạn dừng nói chung là lớn hơn (do có nhiều đống hơn cần kiểm tra). Trong các JVM thời gian thực WebSphere của IBM, bạn có thể điều chỉnh kích thước đống bằng tuỳ chọn -Xmx<size>. Thí dụ, -Xmx512m quy định một đống 512MB. Bạn cũng có thể điều chỉnh việc sử dụng ứng dụng. Ví dụ, - Xgc:targetUtilization=80 đặt nó ở mức 80%. Các đoạn dừng nạp lớp Java Đặc tả ngôn ngữ Java đòi hỏi các lớp phải được giải quyết, nạp, xác thực, và khởi tạo khi có ứng dụng đầu tiên tham chiếu đến chúng. Nếu tham chiếu đầu tiên đến một lớp C xuất hiện trong thời gian có một phép toán chiếm nhiều thời gian, thì thời gian để giải quyết, xác thực, nạp, và khởi tạo C có thể làm cho phép toán đó mất nhiều thời gian hơn được chờ đợi. Do việc nạp C gồm cả việc xác thực lớp đó — mà có thể yêu cầu phải nạp các lớp khác — trễ toàn bộ ứng dụng Java xảy ra để có thể sử dụng một lớp cụ thể đối với lần đầu tiên với thời gian có nghĩa lâu hơn dự kiến. Tại sao một lớp chỉ có thể được tham chiếu đến lần đầu tiên sau đó trong một khai thác ứng dụng? Các đường dẫn được khai thác rất hiếm là nguyên nhân phổ biến của một việc nạp lớp mới. Ví dụ, bộ mã trong Liệt kê 1 chứa một điều kiện if mà rất hiếm được phép khai thác. (để cho ngắn gọn, việc xử lý ngoại lệ và sai sót phần lớn được bỏ qua, từ tất cả các liệt kê trong bài viết này.) Liệt kê 1. Thí dụ về một điều kiện rất hiếm được thực hiện để nạp một lớp mới Iterator<MyClass> cursor = list.iterator(); while (cursor.hasNext()) { MyClass o = cursor.next(); if (o.getID() == 17) { NeverBeforeLoadedClass o2 = new NeverBeforeLoadedClass(o); // do something with o2 } else { // do something with o } } Các lớp ngoại lệ là các ví dụ khác của các lớp mà không được phép nạp cho đến khi chuyển sang hẳn một sự khai thác của ứng dụng, do các ngoại lệ hiếm khi xảy ra (mặc dù không phải luôn thế). Vì các ngoại lệ hiếm khi được xử lý nhanh chóng, việc tăng các quá tải lớp phụ có thể đẩy thời gian chờ phép toán đến ngưỡng gay cấn. Nói chung, các ngoại lệ bị loại bỏ khi có các phép toán chiếm nhiều thời gian phải được tránh đi bất cứ khi nào có thể. Các lớp mới cũng có thể được nạp khi các dịch vụ nào đó, chẳng hạn như phản chiếu, được sử dụng trong thư viện lớp Java. Việc cài đặt ẩn của các lớp phản chiếu tạo ra các lớp mới đang chạy sẽ được nạp trong JVM. Việc sử dụng lặp lại các lớp phản chiếu trong mã nhạy thời gian có thể gây ra hoạt động nạp-lớp liên tục mà đưa ra các trở ngại. Sử dụng tuỳ chọn -verbose:class là cách tốt nhất để phát hiện ra các lớp này đang được tạo ra. Có lẽ cách tốt nhất để tránh việc tạo ra chúng trong thời gian chạy chương trình là tránh sử dụng các dịch vụ phản chiếu để ánh xạ lớp, trường, hoặc các phương thức từ các chuỗi khi chạy các bộ phận tiêu tốn thời gian của ứng dụng của bạn. Thay vào đó, gọi trước các dịch vụ này trong ứng dụng của bạn và lưu các kết quả để sau này sử dụng nhằm ngăn chặn hầu hết các loại lớp này được tạo ra khi đang chạy mà bạn không muốn tạo ra chúng. Một kỹ thuật chung để tránh các trễ khi nạp lớp khi chạy các bộ phận nhạy thời gian của ứng dụng của bạn là nạp trước các lớp khi khởi động hoặc khởi tạo ứng dụng. Mặc dù bước nạp trước này đưa ra một trở ngại khởi động bổ sung nào đó (thật đáng tiếc là, việc cải tiến một độ đo thường gây hậu quả tiêu cực đối với độ đo khác), nếu được sử dụng cẩn thận, có thể loại bỏ việc nạp lớp không mong muốn về sau. Quy trình khởi động này rất dễ thực hiện, như trong Liệt kê 2: Liệt kê 2. Nạp lớp được điều khiển từ một danh sách lớp Iterator<String> classIt = listOfClassNamesToLoad.iterator(); while (classIt.hasNext()) { String className = classIt.next(); try { Class clazz = Class.forName(className); String n=clazz.getName(); } catch (Exception e) { System.err.println("Could not load class: " + className); System.err.println(e); } Hãy chú ý đến lần gọi clazz.getName() nó buộc lớp này phải được khởi tạo. Việc xây dựng danh sách các lớp đòi hỏi phải thu thập thông tin từ ứng dụng của bạn khi nó chạy, hoặc phải sử dụng một tiện ích mà có thể xác định được các lớp nào mà ứng dụng của bạn sẽ nạp. Thí dụ, bạn có thể nắm bắt được kết quả đầu ra của chương trình của bạn khi chạy với tuỳ chọn -verbose:class. Liệt kê 3 trình bày kết quả của lệnh này sẽ trông như thế nào nếu bạn sử dụng một sản phẩm thời gian thực WebSphere của IBM: Liệt kê 3. Trích đoạn kết quả từ việc chạy java với -verbose:class class load: java/util/zip/ZipConstants class load: java/util/zip/ZipFile class load: java/util/jar/JarFile class load: sun/misc/JavaUtilJarAccess class load: java/util/jar/JavaUtilJarAccessImpl class load: java/util/zip/ZipEntry class load: java/util/jar/JarEntry class load: java/util/jar/JarFile$JarFileEntry class load: java/net/URLConnection class load: java/net/JarURLConnection class load: sun/net/www/protocol/jar/JarURLConnection Bằng cách lưu lại danh sách các lớp do ứng dụng của bạn nạp khi khai thác và sử dụng danh sách đó để đưa vào danh sách các tên lớp cho vòng lặp như hiển thị trong Liệt kê 2, bạn có thể chắc chắn rằng các lớp đó nạp trước khi ứng dụng của bạn bắt đầu chạy. Dĩ nhiên, các khai thác khác nhau của ứng dụng của bạn có thể dùng các đường dẫn khác nhau, nên danh sách từ một khai thác có thể không đầy đủ. Chuẩn bị cho điều đó, nếu ứng dụng của bạn đang được phát triển, bộ mã vừa mới viết ra hoặc sửa đổi có thể dựa vào các lớp mới mà không phải là bộ phận của danh sách (hoặc lớp mà nằm trong danh sách có thể không lâu hơn yêu cầu). Đáng tiếc là, việc bảo trì danh sách lớp lại là một phần vô cùng rắc rối khi theo tiếp cận này đối với việc nạp trước lớp. Nếu bạn theo tiếp cận này, hãy nhớ rằng tên của sản phẩm đầu ra lớp của -verbose:class không phù hợp với định dạng mà Class.forName() đòi hỏi: đầu ra rườm rà (verbose output) tách riêng các gói lớp bằng các dấu gạch chéo tiến, khi Class.forName() chờ chúng được tách riêng bằng các dấu chấm câu. Đối với các ứng dụng mà việc nạp lớp là công việc, một số công cụ có thể giúp bạn quản lý việc nạp trước, gồm có Công cụ Phân tích Lớp Thời gian Thực (Real Time Class Analysis Tool - RATCAT) và Bộ Tối ưu hoá Khai thác Ứng dụng Thời gian Thực dùng cho Java của IBM (IBM Real Time Application Execution Optimizer for Java) (xem Tài nguyên). Các công cụ này cung cấp một số kỹ thuật tự động để định danh danh sách các lớp để nạp trước và kết hợp bộ mã nạp trước vào ứng dụng của bạn. Các đoạn dừng biên dịch-mã JIT Vẫn còn một nguồn thứ ba của các trở ngại trong chính JVM là bộ biên dịch JIT. Nó hoạt động khi ứng dụng của bạn chạy để dịch các phương thức của chương trình từ các từ ngôn ngữ máy được bộ biên dịch javac tạo ra thành các chỉ thị riêng của bộ xử lý trung tâm mà ứng dụng chạy trên nó. Bộ biên dịch JIT là cốt yếu đối với sự thành công của nền Java vì nó tạo ra hiệu năng ứng dụng cao mà không phải hi sinh tính trung lập nền của các ngôn ngữ máy Java. Trong thập niên vừa qua và sau này, các kỹ sư biên dịch JIT đã có các bước tiến dài trong việc cải thiện thông lượng và thời gian chờ đối với ứng dụng Java. Một ví dụ về sự tối ưu hoá JIT Một ví dụ tốt về tối ưu hoá JIT là sự chuyên môn hoá về các arraycopy (sao chép mảng/dãy). Đối với một phương thức thường xuyên được thực hiện, bộ biên dịch JIT có thể vẽ biên dạng độ dài của một lần gọi arraycopy riêng để xem liệu các độ dài nhất định là phổ biến nhất hay không. Sau tạo hình lần gọi một lúc, bộ biên dịch JIT có thể thấy rằng chiều dài gần như lúc nào cũng là 12 byte. Với tri thức này, JIT có thể tạo ra một đường dẫn vô cùng nhanh cho lần gọi arraycopy mà sao chép trực tiếp số 12 byte đòi hỏi này theo cách hiệu quả nhất đối với bộ xử lý đích. JIT chèn vào một vận cản có điều kiện để xem độ dài có phải là 12 hay không, và nếu như vậy thì việc sao chép đường dẫn-nhanh siêu hiệu quả sẽ được thực hiện. Nếu độ dài không phải là 12, thì một đường dẫn khác xuất hiện, thực hiện việc sao chép theo kiểu mặc định, nó có thể liên quan đến việc bổ sung lâu hơn nhiều vì nó có thể xử lý bất kỳ độ dài mảng nào. Nếu phần lớn các phép toán trong ứng dụng sử dụng đường dẫn nhanh, thì thời gian chờ hoạt động chung sẽ dựa trên thời gian mà nó mất để sao chép trực tiếp 12 byte đó. Tuy nhiên bất kỳ phép toán nào mà đòi hỏi một sự sao chép của một độ dài khác sẽ xuất hiện để được làm chậm lại liên quan đến việc định thời hoạt động chung. Đáng tiếc là, các cải tiến như vậy đi kèm các đoạn dừng trong hiệu năng ứng dụng Java, do bộ biên dịch JIT “ăn cắp” các chu trình từ chương trình ứng dụng để tạo ra bộ mã được biên dịch (hoặc thậm chí biên dịch lại) cho một phương thức riêng. Tuỳ thuộc vào kích thước của phương thức mà được biên dịch và mức độ tích cực mà JIT chọn để biên dịch nó, thời gian biên dịch có thể có biên độ từ dưới 1 milli- giây đến hơn một giây đối với các phương thức đặc biệt lớn mà được bộ biên dịch JIT quan sát đang góp phần đáng kể vào thời gian thực hiện của ứng dụng. Tuy nhiên hoạt động của bộ biên dịch JIT tự nó không phải là nguồn duy nhất của các biến đổi bất ngờ trong các việc định thời mức ứng dụng. Do các kỹ sư biên dịch JIT đã hầu như chỉ tập trung vào hiệu năng ca trung bình (average-case performance) để cải thiện hiệu năng thông lượng và thời gian chờ một cách hiệu quả nhất, các bộ biên dịch JIT thường thực hiện một loạt các tối ưu hoá mà “thường” là đúng hoặc “chủ yếu” là hiệu năng cao. Trong trường hợp chung, các tối ưu hoá này vô cùng hiệu quả, và kinh nghiệm được phát triển, thực hiện một công việc ráp nối sự tối ưu hoá khá tốt với các tình huống phổ biến nhất khi một ứng dụng đang chạy. Tuy nhiên, trong một số trường hợp thì các tối ưu hoá như vậy có thể đưa ra nhiều mức thay đổi hiệu năng. Ngoài việc nạp trước tất cả các lớp, bạn cũng có thể yêu cầu bộ biên dịch JIT biên dịch hiện các phương thức của các lớp đó khi khởi tạo ứng dụng. Liệt kê 4 mở rộng bộ mã nạp trước lớp trong Liệt kê 2 để điều khiển việc biên dịch phương thức: Liệt kê 4. Biên dịch phương thức được điều khiển Iterator<String> classIt = listOfClassNamesToLoad.iterator(); while (classIt.hasNext()) { String className = classIt.next(); try { Class clazz = Class.forName(className); String n = clazz.name(); java.lang.Compiler.compileClass(clazz); } catch (Exception e) { System.err.println("Could not load class: " + className); System.err.println(e); } } java.lang.Compiler.disable(); // optional Bộ mã này làm cho một tập hợp các lớp được nạp và các phương thức của tất cả các lớp được biên dịch bởi bộ biên dịch JIT. Dòng cuối cùng vô hiệu hoá bộ biên dịch JIT đối với phần còn lại của khai thác ứng dụng. Cách tiếp cận này nói chung làm cho thông lượng tổng thể hoặc hiệu năng thời gian chờ thấp hơn so với việc bộ biên dịch JIT hoàn toàn tự do chọn ra các phương thức sẽ được biên dịch. Do các phương thức không được gọi trước khi bộ biên dịch JIT chạy — bộ biên dịch JIT có ít thông tin hơn nhiều về mức độ tối ưu hóa các phương thức mà nó biên dịch; nên mong chờ các phương thức này thực hiện chậm hơn. Ngoài ra, vì bộ biên dịch bị vô hiệu hóa, không phương thức nào sẽ được biên dịch lại ngay cả khi chúng chịu trách nhiệm về phần lớn thời gian khai thác của chương trình, nên các khung làm việc biên dịch JIT có khả năng thích nghi như các khung được sử dụng trong hầu hết các JVM hiện đại nhất sẽ không hoạt động. Lệnh Compiler.disable() không hoàn toàn cần thiết để giảm bớt một số lớn các đoạn dừng gây-ra-bởi-bộ-biên-dịch-JIT, nhưng các đoạn dừng vẫn còn sẽ vẫn cần dịch trên các phương thức nóng của ứng dụng, thường đòi hỏi các thời gian biên dịch lâu hơn với tác động tiềm tàng cao hơn lên các định thời ứng dụng. Bộ biên dịch JIT trong một JVM riêng không thể được bỏ nạp khi phương thức disable() được gọi, nên có thể vẫn còn bộ nhớ được tiêu thụ, các thư viện được chia sẻ được nạp, và các tạo tác khác của bộ biên dịch JIT có mặt trong giai đoạn thời gian chạy của chương trình ứng dụng. Mức độ tác động của biên dịch mã riêng đến hiệu năng của ứng dụng thay đổi theo ứng dụng. Cách tiếp cận tốt nhất của bạn để xem việc biên dịch có thể là vấn đề hay không là bật đầu ra rườm rà lên, cho biết khi nào các biên dịch xảy ra để xem chúng có thể ảnh hưởng đến các định thời ứng dụng của bạn hay không. Ví dụ, với JVM Thời gian Thực WebSphere của IBM, bạn có thể bật ghi nhật ký rườm rà JIT với dòng lệnh tuỳ chọn -Xjit:verbose. [...]... ứng dụng — nhất là độ đa dạng, mà ảnh hưởng đến chất lượng dịch vụ Việc đưa ra Java thời gian thực đã cho các nhà thiết kế ứng dụng các công cụ mà họ cần phải nhắm đến nguồn thay đổi trong một JVM và trong các ứng dụng của họ để cung cấp chất lượng dịch vụ mà các khách hàng và tác nhân tiêu thụ của họ chờ đợi Bài viết này đã giới thiệu một số kỹ thuật mà bạn có thể sử dụng để sửa đổi một ứng dụng Java. .. đựng các công cụ mà có thể giúp bạn thiết kế các ứng dụng với hành vi thời gian thực; có thể chỉ sử dụng một vài công cụ hoặc có thể viết lại hoàn toàn ứng dụng của bạn để đảm bảo hiệu năng dự tính trước Thường không khó sửa đổi ứng dụng của bạn để sử dụng các RealtimeThread (xử lí Thời gian thực) , và bạn có thể thực hiện điều đó thậm chí không cần có quyền truy cập đến một JVM thời gian thực để biên dịch. .. qua một sự giảm thông lượng khá lớn Dù sao, nếu vài phép toán chạy lâu khó tin nổi, ứng với mức độ chất lượng không thể chấp nhận được, thì sử dụng các RealtimeThread với một JVM thời gian thực có thể chính là giải pháp đúng Tóm lược Trong thế giới của các ứng dụng Java, thông lượng và thời gian chờ theo truyền thống đã trở thành các độ đo được ứng dụng chọn và các nhà thiết kế băng chuẩn để báo cáo... tận dụng ưu điểm của các giá trị ưu tiên sẵn có cho các RealtimeThread sẽ cho bạn cơ hội tốt nhất đáp ứng các mục tiêu chất lượng dịch vụ của bạn (Để có nhiều mách nước hơn về việc sử dụng các RealtimeThread trong ứng dụng của bạn, xin xem "Java thời gian thực, Phần 3: Xử lí và đồng bộ hoá.") Một thí dụ về máy chủ Java Trong phần còn lại của bài này, chúng ta sẽ áp dụng một số ý tưởng đưa ra trong các. .. hoá Lựa chọn này đã có một tác động rộng khắp lên sự tiến hoá của các thời gian chạy Java được xây dựng nên để cải thiện hiệu năng Mặc dù các thời gian chạy Java được khởi động như là các phiên dịch viên với thời gian chờ chạy và thông lượng vô cùng chậm, các JVM hiện đại có thể cạnh tranh tốt với các ngôn ngữ khác về các thước đo này đối với nhiều ứng dụng Mặc dù cho đến thời kỳ tương đối gần đây cũng... trước đây vào một ứng dụng máy chủ Java tương đối đơn giản được xây dựng nên bằng cách sử dụng dịch vụ Executors (Các bộ khai thác) trong Thư viện Lớp Java Chỉ với một lượng nhỏ bé của mã ứng dụng, dịch vụ Executors cho phép bạn tạo ra một máy chủ quản lý vùng đệm cho các xử lí làm việc, như trong Liệt kê 5: Liệt kê 5 Các lớp Server và TaskHandler sử dụng dịch vụ Executors import java. util.concurrent.Executors;... Việc sử dụng thời gian thực bộ gom đã giảm bớt thời gian phép toán tối đa một cách đáng kể, nhưng nó cũng tăng thêm thời gian phép toán kéo dài Tồi hơn nữa, tốc độ truyền thông giảm đáng kể Bước cuối cùng là sử dụng các RealtimeThread — chứ không phải là các xử lí Java thông thường — đối với các xử lí làm việc Chúng ta đã tạo ra một lớp RealtimeThreadFactory cho phép chúng ta có thể cung cấp cho dịch vụ. .. được-AOT-biên dịch Xem phần Tài nguyên để có một liên kết đến tư liệu admincache Quản lý các xử lí Việc điều khiển khai thác của các xử lí trong một ứng dụng đa xử lí chẳng hạn máy chủ giao dịch là cốt yếu đối với việc loại bỏ độ đa dạng trong các lần giao dịch Mặc dù ngôn ngữ lập trình Java định nghĩa một mô hình xử lí, có ý niệm về các ưu tiên xử lí, hành vi của các xử lí trong một JVM thực phần lớn được... khởi động (warm-up loop), cách tiếp cận này có xu hướng riêng cho JVM vì sự suy nghiệm mà bộ biên dịch JIT sử dụng để chọn ra các phương thức để biên dịch khác với các cài đặt JVM Việc sử dụng dịch vụ Compiler.compile() đưa vào hoạt động biên dịch có thể điều khiển được nhiều hơn, nhưng như chúng ta đã đề cập trước đó trong bài viết, chúng ta sẽ chờ đợi sự giảm thông lượng khi dùng tiếp cận này Các. .. các nhà cung cấp, và chúng có thể thay đổi về cả tên và ý nghĩa từ bản phát hành này đến bản tiếp theo Tuy nhiên, một số JVM thay thế có thể cung cấp một vài tuỳ chọn cho bạn, tuỳ thuộc vào mức độ quan trọng các đoạn dừng gây-ra-bởi-bộ-biên -dịch- JIT cho bạn Các JVM thời gian thực được thiết kế để sử dụng trong các hệ thống Java thời gian thực cứng nhìn chung cung cấp nhiều tuỳ chọn hơn Ví dụ thời gian . Phát triển với Java thời gian thực, Phần 2: Cải thiện chất lượng dịch vụ Sử dụng Java thời gian thực để giảm bớt độ đa dạng trong các ứng dụng Java Mark Stoodley, Lãnh đạo Kỹ thuật Thời gian. tốt nhất đáp ứng các mục tiêu chất lượng dịch vụ của bạn. (Để có nhiều mách nước hơn về việc sử dụng các RealtimeThread trong ứng dụng của bạn, xin xem " ;Java thời gian thực, Phần 3: Xử lí. " ;Java thời gian thực, Phần 4: Gom rác Thời gian thực& quot; để được mô tả chi tiết về phép gom rác Thời gian Thực WebSphere của IBM). Kích thước của đống và mức sử dụng ứng dụng là các tuỳ

Ngày đăng: 07/08/2014, 10:22

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan