Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации

Pack200 и Сжатие

Эта глава включает следующие темы:

Введение

Чтобы увеличить сервер и сетевую доступность и пропускную способность, два новых формата сжатия доступны развертыванию Java приложений и апплетов: gzip и Pack200.

С обоими методами сжатые файлы JAR передаются по сети, и приложение получения распаковывает и восстанавливает их.

Теория

HTTP 1.1 (RFC 2616) протокол обсуждает сжатие HTTP. Сжатие HTTP позволяет файлам JAR приложений быть развернутыми как сжатые файлы JAR. Поддерживаемые методы сжатия являются gzip, сжатием, выкачивают.

С версии 5.0 SDK/JRE сжатие HTTP реализуется в Java веб-Запуск и Плагин Java в соответствии с RFC 2616. Поддерживаемые методы являются gzip и pack200-gzip.

Запрашивающее приложение отправляет запрос HTTP серверу. У запроса HTTP есть многократные поля. Принятый закодированный (AE) поле устанавливается в pack200-gzip или gzip, указание к серверу, что приложение может обработать pack200-gzip или gzip формат.

Реализация сервера будет искать требуемый файл JAR с .pack.gz или .gz расширение файла и отвечает назад расположенным файлом. Сервер установит Кодирование контента заголовка ответа (CE) поле к pack200-gzip , gzip, или НУЛЬ в зависимости от типа файла, который отправляется, и дополнительно может установить Тип контента (CT) в application/Java-archive. Поэтому, осматривая поле CE, запрашивающее приложение может применить соответствующее преобразование, чтобы восстановить исходный файл JAR.

Вышеупомянутое может быть достигнуто, используя простой сервлет или модуль сервера с любым HTTP 1.1 совместимых веб-сервера. Сжатие файлов на лету ухудшит производительность сервера, особенно с Pack200, и поэтому не рекомендуемое.

Демонстрационный Сервлет Tomcat:

/**
 *  A simple HTTP Compression Servlet
 */

import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.zip.*;
import java.net.*;

/**
 * The servlet class.
 */
public class ContentType extends HttpServlet {

    private static final String JNLP_MIME_TYPE          = "application/x-java-jnlp-file";
    private static final String JAR_MIME_TYPE           = "application/x-java-archive";
    private static final String PACK200_MIME_TYPE       = "application/x-java-pack200";

    // HTTP Compression RFC 2616 : Standard headers
    public static final String ACCEPT_ENCODING          = "accept-encoding";
    public static final String CONTENT_TYPE             = "content-type";
    public static final String CONTENT_ENCODING         = "content-encoding";

    // HTTP Compression RFC 2616 : Standard header for HTTP/Pack200 Compression
    public static final String GZIP_ENCODING            = "gzip";
    public static final String PACK200_GZIP_ENCODING    = "pack200-gzip";
       
    private void sendHtml(HttpServletResponse response, String s) 
                 throws IOException {
         PrintWriter out = response.getWriter();
         
         out.println("<html>");
         out.println("<head>");
         out.println("<title>ContentType</title>");
         out.println("</head>");
         out.println("<body>");
         out.println(s);
         out.println("</body>");
         out.println("</html>");
    }

    /* 
     * Copy the inputStream to output ,
     */    
    private void sendOut(InputStream in, OutputStream ostream) 
                 throws IOException {
        byte buf[] = new byte[8192];

        int n = in.read(buf);
        while (n > 0 ) {
            ostream.write(buf,0,n);
            n = in.read(buf);
        }
        ostream.close();
        in.close();
    }
    
    boolean doFile(String name, HttpServletResponse response) {
        File f = new File(name);
        if (f.exists()) {
            getServletContext().log("Found file " + name);

            response.setContentLength(Integer.parseInt(
                        Long.toString(f.length())));

            response.setDateHeader("Last-Modified",f.lastModified());
            return true;  
        }
        getServletContext().log("File not found " + name);
        return false;
    }
    
    
    /** Called when someone accesses the servlet. */
    public void doGet(HttpServletRequest request, 
                HttpServletResponse response) 
                throws IOException, ServletException {
        
        String encoding = request.getHeader(ACCEPT_ENCODING);
        String pathInfo = request.getPathInfo();
        String pathInfoEx = request.getPathTranslated();
        String contentType = request.getContentType();
        StringBuffer requestURL  = request.getRequestURL();
        String requestName = pathInfo; 
        
        ServletContext sc = getServletContext();
        sc.log("----------------------------");
        sc.log("pathInfo="+pathInfo);
        sc.log("pathInfoEx="+pathInfoEx);
        sc.log("Accept-Encoding="+encoding);
        sc.log("Content-Type="+contentType);
        sc.log("requestURL="+requestURL);
        
        if (pathInfoEx == null) {
            response.sendError(response.SC_NOT_FOUND);
            return;
        }
        String outFile = pathInfo;
        boolean found = false;
        String contentEncoding = null;
        

        // Pack200 Compression
        if (encoding != null && contentType != null &&
                contentType.compareTo(JAR_MIME_TYPE) == 0 &&
                encoding.toLowerCase().indexOf(PACK200_GZIP_ENCODING) > -1){

            contentEncoding = PACK200_GZIP_ENCODING;
            
            
            if (doFile(pathInfoEx.concat(".pack.gz"),response)) {
                outFile = pathInfo.concat(".pack.gz") ;
                found = true;
            } else {
                // Pack/Compress and transmit, not very efficient.
                found = false;
            }
        }

        // HTTP Compression
        if (found == false && encoding != null &&
                contentType != null &&
                contentType.compareTo(JAR_MIME_TYPE) == 0 && 
                encoding.toLowerCase().indexOf("gzip") > -1) {
                
            contentEncoding = GZIP_ENCODING;

            if (doFile(pathInfoEx.concat(".gz"),response)) {
                outFile = pathInfo.concat(".gz");
                found = true;
            }             
        }

        // No Compression
        if (found == false) { // just send the file
            contentEncoding = null;
            sc.log(CONTENT_ENCODING + "=" + "null");
            doFile(pathInfoEx,response);
            outFile = pathInfo;
        }

        response.setHeader(CONTENT_ENCODING, contentEncoding);
        sc.log(CONTENT_ENCODING + "=" + contentEncoding + 
                " : outFile="+outFile);


        if (sc.getMimeType(pathInfo) != null) {
            response.setContentType(sc.getMimeType(pathInfo));
        }
        
        InputStream in = sc.getResourceAsStream(outFile);
        OutputStream out = response.getOutputStream();

        if (in != null) {
            try {
                sendOut(in,out);
            } catch (IOException ioe) {
                if (ioe.getMessage().compareTo("Broken pipe") == 0) {
                    sc.log("Broken Pipe while writing");
                    return;
                } else  throw ioe;
            }
        } else response.sendError(response.SC_NOT_FOUND);
        
    }

}


Сжатие GZIP

GZIP является компрессором в свободном доступе, доступным в пределах JRE и SDK как Java.util.zip. GZIPInputStream и Java.util.zip. GZIPOutputStream.
Версии Командной строки доступны с большинством Операционных систем Unix, Windows Unix Toolkits (Cygwin и MKS), или они загружаемы для множества операционных систем в http://www.gzip.org/.

Можно получить самую высокую степень сжатия, используя gzip, чтобы сжать несжатый файл фляги по сравнению со сжатием сжатого файла фляги, нижняя сторона - то, что файл может храниться несжатый на целевых системах.

Вот пример:
Сжатие использующий gzip на файле фляги, содержащем человека выкачанные записи.
Notepad.jar    46.25 Кбит
Notepad.jar.gz  43.00 Кбита

Сжатие использующий gzip на файле фляги, содержащем "сохраненные" записи
Notepad.jar    987.47 Кбит
Notepad.jar.gz  32.47 Кбита

Поскольку можно видеть, что размер загрузки может быть уменьшен на 14 %, используя несжатую флягу против 3 %, используя сжатый файл фляги.

Сжатие Pack200

Pack200 сжимает большие файлы очень эффективно, в зависимости от плотности и размера файлов класса в файле JAR. Можно ожидать сжатие к 1/9 размер файла JAR, если это будет содержать только файлы класса и будет в порядке нескольких Мбайт. 

Используя ту же самую флягу в предыдущем примере:
Notepad.jar    46.25 Кбит
Notepad.jar.pack.gz 22.58 Кбита

В этом случае та же самая фляга может быть уменьшена на 50 %.

Пожалуйста, отметьте: подписывая большие фляги, шаг 5 может перестать работать с Ошибкой Безопасности ⠀”, вероятной причиной является ошибка 5078608. Пожалуйста, используйте одно из обходных решений, детализированных в информации о версии.

Pack200 работает наиболее эффективно над файлами класса Java. Это использует несколько методов, чтобы эффективно уменьшить размер файлов JAR:

  1. Это объединяет и сортирует данные постоянного пула в файлах класса и cо-определяет местоположение их в архиве.
  2. Это удаляет избыточные атрибуты класса.
  3. Это хранит внутренние структуры данных.
  4. Это использует кодирование переменной длины и дельта.
  5. Это выбирает типы оптимального кодирования для вторичного сжатия.

Pack200 может использоваться при использовании Интерфейсов командной строки pack200 (1), unpack200 (1) в каталоге bin Вашего SDK или каталога JRE.
Интерфейсы Pack200 могут также вызванный программно от Java, пожалуйста, обратитесь к API и ссылкам JavaDoc на Java.util.jar. Pack200.

Шаги, чтобы Упаковать файл

1. Рассмотрите размер файла JAR, содержание файла JAR, и пропускную способность Вашей целевой аудитории.

Все эти факторы играют в выбор метода сжатия. unpack200 разрабатывается, чтобы быть настолько эффективным насколько возможно, и он занимает время, чтобы восстановить исходный файл. Если у Вас есть большие файлы JAR (2 Мбайта или больше) состоявший главным образом из файлов класса, Pack200 является привилегированным методом сжатия. Если у Вас есть большие файлы JAR, которые состоят из файлов ресурсов (JPEG, ДЖИФ, данные, и т.д.), то gzip является привилегированным методом сжатия.

2. Сегментация Pack200.

Pack200 загружает весь упакованный файл в память. Однако, когда целевые системы являются памятью и ограниченным ресурсом, устанавливая Pack200.Packer.SEGMENT_LIMIT к нижнему значению, уменьшит требования к памяти во время упаковки и распаковки. Pack200.Packer.SEGMENT_LIMIT=-1 вынудит один сегмент быть сгенерированным, который будет эффектом в сокращении размера, но потребует, чтобы намного больший Java свалил в кучу упаковку и распаковку системы. Отметьте, что несколько из этих упакованных сегментов могут быть связаны, чтобы произвести единственный упакованный файл.

3. Подписание файлов JAR.

Pack200 перестраивает содержание результирующего файла JAR. jarsigner хеширует содержание файла класса и хранит хеш в зашифрованном обзоре в декларации. Когда неупаковщик будет работать на упакованном упакованном, содержание классов будет перестроено и таким образом лишит законной силы подпись. Поэтому, файл JAR должен быть нормализован, сначала используя pack200 и unpack200, и после того подписан.

(Вот то, почему это работает: Любое переупорядочение упаковщика делает любых classfile структур, идемпотент, таким образом, вторая упаковка не изменяет упорядочивания, произведенные первой упаковкой. Кроме того, неупаковщику гарантирует JSR 200 спецификаций, чтобы произвести определенное изображение bytewise для любого данного упорядочивания передачи элементов архива.)

Пример

Предположите, что Вы хотите использовать HelloWorld.jar.


Шаг 1:  Перепакуйте файл, чтобы нормализовать флягу, перепаковывая вызовы упаковщик, и распаковывает файл за один шаг.

% pack200 --repack HelloWorld.jar

Шаг 2: Подпишите флягу после того, как мы нормализуем использование, перепаковывают.

% jarsigner -keystore myKeystore HelloWorld.jar ksrini

Проверьте справедливую флягу со знаком, чтобы гарантировать работавшее подписание.

% jarsigner -verify HelloWorld.jar
jar verified.


Гарантируйте, что фляга все еще работает.

% Java -jar HelloWorld.jar
HelloWorld


Шаг 3: Теперь мы упаковываем файл

% pack200 HelloWorld.jar.pack.gz HelloWorld.jar

Шаг 4: Распакуйте файл

% unpack200 HelloWorld.jar.pack.gz HelloT1.jar

Шаг 5:  Проверьте флягу

% jarsigner -verify HelloT1.jar
jar verified.


//Протестируйте флягу...
% Java -jar HelloT1.jar
HelloWorld


После проверки сжатый файл пакета может быть развернут HelloWorld.jar.pack.gz.

4. Методы сокращения: 

 Pack200 по умолчанию ведет себя в Высоком качестве (Магнитофон) режим, означая, что все исходные атрибуты, существующие в классах так же как атрибутах каждой отдельной записи в файле JAR, сохраняются. Они обычно имеют тенденцию добавлять к упакованному размеру файла, вот некоторые из методов, которые можно использовать, чтобы далее уменьшить размер загрузки:
  1. Время изменения: Если время изменения отдельных записей в файле JAR не является беспокойством, можно определить опцию  Pack200.Packer.MODIFICATION_TIME="LATEST". Это позволит одному времени изменения быть переданным в файле пакета для каждого сегмента. Последнее время будет последним временем любой записи в пределах того сегмента. 
  2. Подсказка дефляции: Подобный вышеупомянутому, если состояние сжатия отдельных записей в архиве не требуется, устанавливает Pack200. Упаковщик. DEFLATION_HINT = "ложь". Это незначительно уменьшит размер загрузки, поскольку отдельные подсказки сжатия не будут переданы. Однако, фляга когда реконструировано будет содержать "сохраненные" записи и следовательно может использовать больше дискового пространства на целевой системе.

    Например:

    pack200 --modification-time=latest --deflate-hint="true" tools-md.jar.pack.gz tools.jar

    Отметьте: вышеупомянутая оптимизация приведет к лучшим результатам с файлом JAR, содержащим тысячи записей.

  3. Атрибуты: Несколько атрибутов класса не требуются, развертывая файлы JAR. Эти атрибуты могут быть разделены из файлов класса, значительно уменьшая размер загрузки. Однако, забота должна быть проявлена, чтобы гарантировать, что сохраняются необходимые атрибуты времени выполнения.
    1. Отладка атрибутов: Если отладочная информация, такая как Номера строки и Исходный файл, не требуется (обычно в трассировках стека приложений), то эти атрибуты могут быть отброшены, определяя Pack200.Packer.STRIP_DEBUG=true.Это обычно уменьшает упакованный файл приблизительно на 10 %.

      Пример:
      pack200 --strip-debug tools-stripped.jar.pack.gz tools.jar

    2. Другие атрибуты: Усовершенствованные пользователи могут использовать некоторые из других связанных с полосой свойств, чтобы разделить дополнительные атрибуты. Однако, экстремальное предостережение должно использоваться, делая так, результирующий файл JAR должен быть протестирован на всех возможных системах Среды выполнения Java, чтобы гарантировать, что время выполнения не зависит от разделенных атрибутов.

5. Обработка неизвестных атрибутов:

Соглашения Pack200 со стандартными атрибутами, определенными Спецификацией виртуальной машины Java, однако компиляторы, являются бесплатными представить пользовательские атрибуты. Когда такие атрибуты присутствуют, по умолчанию, Pack200 проходит через класс, испуская предупреждающее сообщение. Они "проходили" через файлы класса, может способствовать чрезмерному увеличению размера упакованных файлов. Если неизвестные атрибуты распространены в классах файла JAR, это может привести к очень большому чрезмерному увеличению размера упакованного вывода. В таких случаях рассмотрите следующие стратегии:

Разделите атрибут, если атрибут , как считают, избыточен во время выполнения, это может быть достигнуто, устанавливая свойство Pack200. Упаковщик.UNKNOWN_ATTRIBUTE=STRIP or

pack200 --unknown-attribute=strip foo.pack.gz foo.jar

Если атрибуты требуются во время выполнения, и они действительно способствуют инфляции, то идентифицируют атрибут из предупреждающего сообщения и применяют подходящее расположение для них, как описано в Pack200 JSR 200 спецификаций., и ссылочный раздел API Java для Pack200. Упаковщик.

Через его возможное, что компилятор мог определить атрибут, не реализованный в спецификации расположения Pack200, и может заставить Пакера неправильно функционировать в таких случаях весь файл (ы) класса, можно "пройти", как будто это было ресурсом на основании своего имени и может быть определено следующим образом:

pack200 --pass-file="com/acme/foo/bar/baz.class" foo.pack.gz foo.jar

или весь каталог и его содержание,

pack200 --pass-file="com/acme/foo/bar/" foo.pack.gz foo.jar

6. Установщики:

Можно хотеть использовать в своих интересах технологию Pack200 в своей программе установки, посредством чего флягам продукта, возможно, понадобится к сжатому использованию Pack200 и распакованный во время установки. Если  JRE или SDK связываются в установке, Вы свободны использовать unpack200 (Unix) или unpack200.exe (Windows) в каталоге 'мусорного ведра' распределения, эта реализация является чистым приложением C++, не требующим, чтобы никакая Среда выполнения Java присутствовала для этого, чтобы работать.

Windows: Установщики могут использовать лучший алгоритм чем тот в GZIP, чтобы сжать записи в таких случаях, каждый получит лучшее сжатие, используя внутреннее сжатие Установщика, при использовании pack200 следующим образом:

pack200 --no-gzip foo.jar.pack foo.jar

Это будет препятствовать тому, чтобы выходной файл был сжатым gzip.

unpack200 является Windows Console application, то есть он выведет на экран окно MS-DOS во время установки, чтобы подавить это, можно использовать средство запуска с WinMain, который подавит это окно, как показано ниже.

Пример кода:

#include "windows.h"
#include <stdio.h>

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow) {
  STARTUPINFO si;
  memset(&si, 0, sizeof(si));
  si.cb = sizeof(si);

  PROCESS_INFORMATION pi;
  memset(&pi, 0, sizeof(pi));

  //Test
  //lpCmdLine = "c:/build/windows-i586/bin/unpack200 -l c:/Temp/log c:/Temp/rt.pack c:/Temp/rt.jar";
  int ret = CreateProcess(NULL,                 /* Exec. name */
                          lpCmdLine,            /* cmd line */
                          NULL,                 /* proc. sec. attr. */
                          NULL,                 /* thread sec. attr */
                          TRUE,                 /* inherit file handle */
                          CREATE_NO_WINDOW | DETACHED_PROCESS, /* detach the process/suppress console */
                          NULL,                 /* env block */
                          NULL,                 /* inherit cwd */
                          &si,                      /* startup info */
                          &pi);                     /* process info */
  if ( ret == 0) ExitProcess(255);

  // Wait until child process exits.
  WaitForSingleObject( pi.hProcess, INFINITE );

  DWORD exit_val;

  // Be conservative and return
  if (GetExitCodeProcess(pi.hProcess, &exit_val) == 0) ExitProcess(255);

  ExitProcess(exit_val); // Return the error code of the child process

  return -1;
}

Тестирование

Требуется, что все файлы JAR, упаковали и распаковали, быть протестированными на правильность с Вашими приложениями тестируют спецификаторы. При использовании интерфейса командной строки pack200, выходной файл будет сжат, используя gzip со значениями по умолчанию. Пользователь может создать простой файл пакета и использование сжатия gzip с определенными пользователем опциями или использующий некоторый другой компрессор.

Больше информации

Для получения дополнительной информации см. pack200 и unpack200 в Инструментах Развертывания Java.

Обновления в Java Standard Edition 6

В Java SE 6, был обновлен формат файла класса Java. Для получения дополнительной информации см. JSR 202: Обновление Спецификации Файла Класса Java. Из-за JSR 202 механизм Pack200 должен быть обновлен соответственно по следующим причинам:

Чтобы сохранить изменения минимальными и без шва для пользователей, упаковщик генерирует соответственно имеющие версию файлы пакета, основанные на версии входных файлов класса.

Также, чтобы поддержать обратную совместимость, если входные файлы JAR исключительно состоят из JDK 1.5 или более старых файлов класса, 1.5 совместимых файла пакета производятся. Иначе Java SE 6 совместимых pack200 файлов производится. Для получения дополнительной информации отошлите страницу справочника Pack200.


Oracle и/или его филиалы Авторское право © 1993, 2011, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами