java ProGuard 删除(收缩)未使用的类

发布于 2024-11-29 07:52:03 字数 2030 浏览 1 评论 0原文

假设我有这个 Java 应用程序:

package com.site;

public class MyAppBase {}

package com.site.free;

import com.site.MyAppBase;

public class MyApp extends MyAppBase {}

package com.site.pro;

import com.site.MyAppBase;

public class MyApp extends MyAppBase {}

package com.site;

public class Edition
{

    public static final int     FREE    = 1;
    public static final int     PRO     = 2;

    private static final int    EDITION = PRO;

    public static boolean is(final int edition)
    {
        return (EDITION == edition);
    }
}

package com.site;

public class EditionFactory
{

    public static MyAppBase get_app()
    {
        MyAppBase ret = null;

        if (Edition.is(Edition.FREE))
            ret = new com.site.free.MyApp();
        else if (Edition.is(Edition.PRO))
            ret = new com.site.pro.MyApp();

        return ret;
    }
}

现在,我试图摆脱非选定版本(在本例中它是免费的)的 ProGuard 配置的任何组合都不起作用。

我所说的“摆脱”是指让实际的类消失(以及从调用代码中消失)。

换句话说,像这样的调用:

final MyAppBase app = EditionFactory.get_app();

.. 目前正在被翻译成,在 ProGuarding 之后,这个:

if (a.a(1))
    localObject5 = new c(); // <<< FREE
else if (a.a(2))
    localObject5 = new d(); // <<< PRO

.. 而我希望它被翻译成这样:

localObject5 = new d(); // <<< PRO only in the code (as set at Edition.EDITION)

底线是 (除了 ProGuard 非常棒!!),我似乎无法让它“看穿”并理解 Edition.is() 是一个返回常量的布尔函数这样就可以删除一些类。

我尝试过如下配置:

-keep,allowshrinking,allowoptimization public class * extends com.site.MyAppBase
-optimizationpasses 10

..没有任何效果。

另一方面,如果我引用 Edition.EDITION 并内联比较它(即没有任何“代理”函数),Java 编译器 (v1.6) 会检测到它并删除对非精选版本/类别。
这导致 ProGuard 删除/缩小未使用的类,这很棒。

这里唯一的问题是关于维护 - 我很高兴能够继续使用 EditionFactory 风格。

Let's say I have this Java app:

package com.site;

public class MyAppBase {}

package com.site.free;

import com.site.MyAppBase;

public class MyApp extends MyAppBase {}

package com.site.pro;

import com.site.MyAppBase;

public class MyApp extends MyAppBase {}

package com.site;

public class Edition
{

    public static final int     FREE    = 1;
    public static final int     PRO     = 2;

    private static final int    EDITION = PRO;

    public static boolean is(final int edition)
    {
        return (EDITION == edition);
    }
}

package com.site;

public class EditionFactory
{

    public static MyAppBase get_app()
    {
        MyAppBase ret = null;

        if (Edition.is(Edition.FREE))
            ret = new com.site.free.MyApp();
        else if (Edition.is(Edition.PRO))
            ret = new com.site.pro.MyApp();

        return ret;
    }
}

Now, any combination of ProGuard configuration I'm trying to get rid of the non-selected edition (in this case it's FREE) doesn't work.

By "getting rid of" I mean make the actual class disappear (as well from the calling code).

In other words, a call like this:

final MyAppBase app = EditionFactory.get_app();

.. is currently being translated to, after ProGuarding it, this:

if (a.a(1))
    localObject5 = new c(); // <<< FREE
else if (a.a(2))
    localObject5 = new d(); // <<< PRO

.. while I'd wish it to be translated to this:

localObject5 = new d(); // <<< PRO only in the code (as set at Edition.EDITION)

Bottom line is (besides the fact that ProGuard is GREAT!!), I can't seem to make it "see through" and understand that Edition.is() is a boolean function returning a constant which makes it ok to remove some classes.

I've tried configurations like:

-keep,allowshrinking,allowoptimization public class * extends com.site.MyAppBase
-optimizationpasses 10

.. nothing works.

On the other hand, if I refer to Edition.EDITION and comparing it inlined (i.e without any "proxy" functions), the Java compiler (v1.6) detects it and remove the whole reference to the non-selected edition/class.
This results in that ProGuard removes/shrinks the unused class which is great.

The only issue here is about maintaining - I'd be happy to keep being able to use the EditionFactory style.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

深者入戏 2024-12-06 07:52:03

未执行优化是因为 ProGuard 决定不内联方法 Edition#is,因此它无法简化生成的一系列指令。该方法不是内联的,因为它不是很短并且也被多次调用。您可以使用 ProGuard 的未记录的 JVM 选项来解决第一个标准:

-Dmaximum.inlined.code.length=16

或者,您可以通过确保该方法仅调用一次来解决第二个标准:

return Edition.is(Edition.FREE) ?
    new com.site.free.MyApp() :
    new com.site.pro.MyApp();

或者,您可以创建短函数 isFree() 和 isPro() ,因为它们会返回常量,这些常量将被内联。

如果您期望进行一些特定的优化,最好检查已处理的代码,因为它们通常受到复杂的约束。

很高兴听到您喜欢 ProGuard。

The optimization isn't performed because ProGuard decides not to inline the method Edition#is, so it then can't simplify the resulting series of instructions. The method is not inlined because it is not very short and it is also invoked more than once. You could work around the first criterion with this undocumented JVM option for ProGuard:

-Dmaximum.inlined.code.length=16

Alternatively, you could work around the second criterion, by making sure the method is only invoked once:

return Edition.is(Edition.FREE) ?
    new com.site.free.MyApp() :
    new com.site.pro.MyApp();

Alternatively, you could probably create short functions isFree() and isPro(), because they would return constants, which would be inlined.

It's a good practice to check the processed code if you're expecting some particular optimizations, because they are often subject to complex constraints.

Nice to hear that you like ProGuard.

作死小能手 2024-12-06 07:52:03

这是因为您的方法 is(...) 只能接受比 1 和 2 更多的值。它可以在代码的其他地方用 3, 4, 6... 调用,Proguard 不能排除这种情况。

问题的解决方案是将 Edition 设为 enum。您不再需要 is(...) 方法,并且可以依赖 equals(...)

It is because your method is(...) can take in more values than 1 and 2 only. It could be called elsewhere from the code with 3, 4, 6... Proguard cannot exclude that case.

The solution to your issue is to make Edition an enum. You would not need the is(...) method anymore and could rely on equals(...).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文